编译时断言?

有什么办法可以断言两个常量expression式在编译时是相等的吗?

例如我想这会导致编译时错误

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) 

请参阅static_assert (仅限C ++ 0x); 如果在旧版本上,请参阅Boost的StaticAssert

是。 你可以使用types为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> } 

代码基本上来自内存,可能需要一些调整。

对于静态断言的另一个版本,你可以通过添加一个更好的名字来美化,你可以使用:

 // 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,则定义它。

你可以这样定义你自己的静态断言:

 #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的解决scheme类似,不幸的是,它仅在运行时才有用:

 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] 

静态成员函数/构造函数/字段赋值/隐私和模板规范的组合可能产生不同的结果,可能更适合您的情况。

还有一个技巧是使用switch (..)语句。 那种老风格虽然。 case条目foo == bar必须被编译时间评估,如果碰巧是false,switch语句会导致错误。 编译器也将它减less到“没有”。

 { bool x=false; switch (x) { case foo == bar: break; case false: // Compile time test that foo == bar break; } 
 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_asserts。

  • 提高:: static_assert
  • C ++ 0x static_assert

但是,因为我从来没有尝试过,所以我写这个:

 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 

我build议看一下Eigen库的静态断言机制:

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