静态断言非常便于在编译时检查事物。一个简单的静态断言习惯用法如下:
template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};
#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0)
这对像
这样的东西很有用STATIC_ASSERT(sizeof(float) == 4)
和
#define THIS_LIMIT (1000)
...
STATIC_ASSERT(THIS_LIMIT > OTHER_LIMIT);
但是使用#define
不是定义常量的“C ++”方式。 C ++会让你使用匿名命名空间:
namespace {
const int THIS_LIMIT = 1000;
}
甚至:
static const int THIS_LIMIT = 1000;
问题在于const int
使用STATIC_ASSERT()
时无法使用static const int THIS_LIMIT = 1000;
...
STATIC_ASSERT(THIS_LIMIT > 0);
,您必须采用愚蠢的运行时检查。
有没有办法在当前的C ++中正确解决这个问题? 我想我已经读过C ++ 0x有一些工具可以做到这一点......
修改
好的,这个
static const float THIS_LIMIT = 1000.0f;
...
STATIC_ASSERT(THIS_LIMIT > 0.0f);
编译好 但是这个:
{{1}}
没有。
(在Visual Studio 2008中)
怎么回事?
答案 0 :(得分:11)
为什么,你仍然可以使用const int静态断言:
#define static_assert(e) extern char (*ct_assert(void)) [sizeof(char[1 - 2*!(e)])]
static_assert( THIS_LIMIT > OTHER_LIMIT )
另外,use boost!
BOOST_STATIC_ASSERT( THIS_LIMIT > OTHER_LIMIT )
...您将获得很多更好的错误消息...
答案 1 :(得分:5)
static_assert
是C ++ 0x中的编译器功能,所以只要你有一个相对最新的编译器就可以使用它。注意做#define static_assert(x) ...
,因为它是C ++ 0x中的一个真正的关键字,所以你永远隐藏了编译器功能。此外,C ++ 0x static_assert
有两个参数(例如static_assert(sizeof(int) == 4, "Expecting int to be 4 bytes")
),因此如果你使用#define,你可能会在将来尝试切换时遇到问题。
答案 2 :(得分:2)
您似乎确实询问为什么会出现以下情况(我可以在GCC 4.3.4和Visual C ++ 2008 Express中确认):
template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};
#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0)
static const int AN_INT = 1000;
static const float A_FLOAT = 1000.0f;
int main()
{
STATIC_ASSERT(AN_INT > 0); // OK
STATIC_ASSERT(A_FLOAT > 0.0f); // Error: A_FLOAT may not appear in a constant expression
}
静态使用浮点值有许多限制。例如,请注意,您不能将它们作为模板参数传递。那是因为:
[C++11: 5.19/2]:
条件表达式是核心常量表达式,除非它涉及下列其中一项作为潜在评估的子表达式(3.2),但子表达式不考虑未评估的逻辑AND(5.14),逻辑OR(5.15)和条件(5.16)操作[注意:重载运算符调用 功能。 -end note ] :
- [..]
- 左值到右值的转换(4.1),除非它适用于
- 整数或枚举类型的glvalue ,它指的是具有先前初始化的非易失性const对象,使用常量表达式初始化,或
- 一个文字类型的glvalue,它指的是用constexpr定义的非易失性对象,或引用这种对象的子对象,或
- 一个文字类型的glvalue,它指的是一个生命周期尚未结束的非易失性临时对象,用一个常量表达式初始化;
- [..]
(即只允许使用整数和枚举类型;没有浮点类型。)
至于这条规则的原因,我并不完全确定,但以下几种理由可能与它有关:
[C++11: 5.19/4]:
[..]由于本国际标准对此没有任何限制 浮点运算的准确性,未指定在转换期间对浮点表达式的求值是否产生与对同一表达式的评估相同的结果(或对相同值的相同操作)<强>在程序执行期间。 [..]
答案 3 :(得分:1)
也许你把C ++的行为与C混淆了,其中const int
并不代表真正的编译时常量。或许你的C ++编译器坏了。如果确实是后者,请改用enum
。
答案 4 :(得分:1)
这:
namespace {
const int THIS_LIMIT = 1000;
}
template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};
#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0)
int main()
{
STATIC_ASSERT(THIS_LIMIT > 5);
return (0);
}
用VC和Comeau编译好。
答案 5 :(得分:0)
enum{THIS_LIMIT = 1000};