编译时断言
Compile-time assertion?
有没有一种方法可以在编译时断言两个常量表达式相等?
例如,我希望这会导致编译时错误
enum { foo=263, bar=264 };
SOME_EXPRESSION(foo,bar)
但我希望这不会导致错误
enum { foo=263, bar=263 };
SOME_EXPRESSION(foo,bar)
编辑:以上内容已简化。我的情况更像
some_other_file_I_dont_control.h:
class X
{
public:
enum { foo=263 };
}
my_file.h:
enum { bar=something+somethingelse }; // bar should equal X::foo
SOME_EXPRESSION(X::foo, bar)
是。你可以用bool类型的模板专门化来实现这一点,比如:
// empty default template
template <bool b>
struct StaticAssert {};
// template specialized on true
template <>
struct StaticAssert<true>
{
static void assert() {}
};
int f()
{
StaticAssert<1==1>::assert(); // compiles fine, assert() member found
StaticAssert<1==2>::assert(); // compile failure, no assert() member for StaticAssert<false>
}
代码基本上来自内存,可能需要一些调整。
请参阅static_assert
(仅限C++0x(;如果在旧版本上,请参阅Boost的StaticAssert
。
对于静态断言的另一个版本,您可以通过添加更好的名称来美化它,您可以使用:
// name must be a valid identifier
#define STATIC_ASSERT( condition, name )
typedef char assert_failed_ ## name [ (condition) ? 1 : -1 ];
并用作:
STATIC_ASSERT( x == y, constants_must_be_same );
编译器将触发类似以下的错误:
size of array 'assert_failed_constants_must_be_same' is negative
这似乎没有什么帮助,但它会指向断言的确切行,过一段时间后,您将开始处理该错误消息,因为静态断言失败
Windows的另一种可能性是C_ASSERT,它是在包含Windows.h的情况下定义的。
还有使用switch (..)
语句的技巧。不过有点过时了。case条目foo==bar必须在编译时进行评估,如果它恰好为false,则switch语句将导致错误。编译器还将把它简化为"无"。
{
bool x=false;
switch (x) {
case foo == bar:
break;
case false:
// Compile time test that foo == bar
break;
}
您可以通过以下方式定义自己的静态断言:
#include <iostream>
template <bool b> class ClassStaticAssert;
template <>
class ClassStaticAssert<true>{static const bool value = true;};
#define STATIC_ASSERT(e) (ClassStaticAssert<e>())
int main()
{
STATIC_ASSERT(0);
return 0;
}
类似于iammillind的解决方案,不幸的是,它只在运行时有用:
template <int A, int B>
class VALUES {
};
// specialization to provide safe passage for equal values
template <int X>
class VALUES<X, X> {
public:
static void MY_VALUES_ARE_EQUAL() {}
};
#define ASSERT_EQUALITY(a, b)
{
typedef VALUES<a, b> COMPILE_TIME_ASSERTION;
COMPILE_TIME_ASSERTION::VALUES_ARE_EQUAL();
}
int main() {
ASSERT_EQUALITY(1, 1); // compiles just fine
ASSERT_EQUALITY(1, 2); // ERROR!
// . . .
}
这样做的好处是它提供了一个很好的编译器消息。我的编译器告诉我以下内容:
"VALUES_ARE_EQUAL"不是"COMPILE_TIME_ASSERTION{aka VALUES<1,2>}"的成员
你不需要typedef。无:
"VALUES_ARE_EQUAL"不是"VALUES<1,2>'
当然,还有很多其他方法可以生成有用的消息。咯咯笑:
// these give use some tips in the compiler warnings
class COMPILE_TIME_EQUALITY_ASSERTION {} compiler_message;
class EQUAL_VALUES_ONLY_PLEASE {};
template <int A, int B>
class VALUES {
public:
static void AreEqual(EQUAL_VALUES_ONLY_PLEASE) {}
};
template <int X>
class VALUES<X, X>
{
public:
static void AreEqual(COMPILE_TIME_EQUALITY_ASSERTION) {}
};
#define ASSERT_EQUALITY(a, b)
{
VALUES<a, b>::AreEqual(compiler_message);
}
int main() {
ASSERT_EQUALITY(1, 1) // a-okay
ASSERT_EQUALITY(1, 2) // ERROR!
}
我得到以下编译器错误:
no matching function for call to:
‘VALUES<1,2>::AreEqual(COMPILE_TIME_EQUALITY_ASSERTION&)'
candidate is:
static void VALUES<A, B>::AreEqual(EQUAL_VALUES_ONLY_PLEASE) [with int A = 1, int B = 2]
静态成员函数/构造函数/字段分配/隐私和模板规范的组合可以产生不同的结果,也许更适合您的情况。
template <int a, int b>
inline void static_assert_equal()
{
typedef char enum_values_must_be_equal[a == b ? 1 : -1];
(void) sizeof(enum_values_must_be_equal);
}
int main()
{
enum { foo = 1, bar = 2, fum = foo };
static_assert_equal<foo, fum>(); // compiles ok
static_assert_equal<foo, bar>(); // fails at compile time
return 0;
}
这源于checked_delete
习语。
你可以做一些像这样的预处理器魔术
#define FOO_VALUE 263
#define BAR_VALUE 264
enum {foo=FOO_VALUE, bar=BAR_VALUE}
#if !(FOO_VALUE == BAR_VALUE)
#error "Not equal"
#endif
我会选择一个可用的static_assels。
- boost::static_assert
- C++0x静态断言
但正是因为我以前从未尝试过,所以我写了这个:
enum { foo=263, bar=264 };
template<bool test>
struct CompileAssert
{
bool assert() {}
};
template<>
struct CompileAssert<false> {}; // fail on false.
int main()
{
CompileAssert<foo != bar>().assert(); // Now I have seen Chad above I like his static
CompileAssert<foo == bar>().assert(); // method better than using a normal method.
} // But I tried zero length arrays first did
// not seem to work
我建议看看特征库的静态断言机制:
http://eigen.tuxfamily.org/dox/StaticAssert_8h_source.html
template<int X, int Y>
struct Check
{
enum { value = false };
};
template<int X>
struct Check<X,X>
{
enum { value = true };
};
我举了int
的例子。您可以根据需要进行更改。这是演示。用法:
Check<foo, bar>::value
- 二叉排序树无法编译
- 编译时未启用intel oneApi CUDA支持
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 编译包含字符串的代码时遇到问题
- 编译时断言不可靠
- 静态断言,如果在编译时不知道表达
- C++:编译时断言浮点数的值
- 用于检查编译时间常数的静态断言未传递给宏
- 在没有-DNDEBUG和-O3的情况下编译时,标准库实现不使用断言有什么原因吗
- 在QT框架中编译比特币-QT应用程序时断言失败错误
- 是否可以在C++中使用编译时断言
- G++ 不编译带有断言的 constexpr 函数
- 带有自定义消息的基于模板的编译时断言只能在某些编译器中编译
- 如何创建一个编译时断言模板是特定类型的?
- 编译时对数据类型大小进行断言
- c++中的编译时断言
- c++编译类型资源所有者断言
- 如何断言应该使用c++ 11来编译我的程序
- 编译时断言
- 编译时断言,当并非所有枚举值都在 C++ 的 switch 语句中处理时