[英]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 };
}
我的文件.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>
}
代碼基本上來自 memory,可能需要一些調整。
參見static_assert
(僅限 C++0x); 如果在舊版本上,請參閱Boost 的StaticAssert
。
對於 static 斷言的另一個版本,您可以通過添加更好的名稱來美化,您可以使用:
// 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
這似乎沒有多大幫助,但它會指向斷言的確切行,一段時間后您將開始處理該錯誤消息,因為static 斷言失敗
Windows 的另一種可能性是C_ASSERT ,如果包含 Windows.h 則定義。
還有使用switch (..)
語句的技巧。 不過有點老套路。 案例條目 foo == bar 必須在編譯時進行評估,如果它碰巧為假,則 switch 語句將導致錯誤。 編譯器還會將其減少為“無”。
{
bool x=false;
switch (x) {
case foo == bar:
break;
case false:
// Compile time test that foo == bar
break;
}
您可以這樣定義自己的 static 斷言:
#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]
static 成員函數/構造函數/字段分配/隱私和模板規范的組合可以產生不同的結果,可能更適合您的情況。
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
習慣用法。
我建議看一下 Eigen 庫 static 斷言機制:
你可以做一些預處理器魔法,比如
#define FOO_VALUE 263
#define BAR_VALUE 264
enum {foo=FOO_VALUE, bar=BAR_VALUE}
#if !(FOO_VALUE == BAR_VALUE)
#error "Not equal"
#endif
我會 go 獲得可用的 static_asserts 之一。
但只是因為我在寫這個之前從未嘗試過:
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
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.