编译时断言?
有什么办法可以断言两个常量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库的静态断言机制:
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