什么是static_assert做什么,你会使用它?

你可以举一个例子, static_assert(...) 'C++0x'将优雅地解决手中的问题?

我熟悉运行时assert(...) 。 我应该什么时候比常规assert(...)更喜欢static_assert(...) assert(...)

另外,在boost有一个叫做BOOST_STATIC_ASSERT东西,和static_assert(...)吗?

closures我的头顶…

 #include "SomeLibrary.h" static_assert(SomeLibrary::Version > 2, "Old versions of SomeLibrary are missing the foo functionality. Cannot proceed!"); class UsingSomeLibrary { // ... }; 

假设SomeLibrary::Version被声明为一个静态常量,而不是被定义为#define d(正如在C ++库中所期望的那样)。

与必须实际编译SomeLibrary和您的代码,链接所有内容,然后运行可执行文件才能发现您花了30分钟时间编译SomeLibrary的不兼容版本SomeLibrary

@Arak,回应你的评论:是的,你可以让static_assert从任何地方坐下来:

 class Foo { public: static const int bar = 3; }; static_assert(Foo::bar > 4, "Foo::bar is too small :("); int main() { return Foo::bar; } 
 $ g ++ --std = c ++ 0x a.cpp
 a.cpp:7:错误:静态断言失败:“Foo :: bar太小:(”

静态断言用于在编译时进行断言。 当静态断言失败时,程序根本不编译。 这在不同情况下非常有用,例如,如果您通过严格依赖于具有32位的unsigned int对象的代码来实现一些function。 你可以把这个静态断言

 static_assert(sizeof(unsigned int) * CHAR_BIT == 32); 

在你的代码中。 在另一个平台上,使用不同大小的unsigned inttypes,编译将会失败,从而引起开发人员注意代码中有问题的部分,并build议他们重新执行或重新检查它。

另一个例子,你可能想要传递一个整数值作为一个void *指向一个函数(一个黑客,但有时有用),你想确保整数值将适合指针

 int i; static_assert(sizeof(void *) >= sizeof i); foo((void *) i); 

您可能想要资产该chartypes签名

 static_assert(CHAR_MIN < 0); 

或者负值的积分除以零

 static_assert(-5 / 2 == -2); 

等等。

运行时断言在许多情况下可以用来代替静态断言,但是运行时断言只在运行时才起作用,并且只有在控制通过断言时才起作用。 由于这个原因,失败的运行时间断言可能处于hibernate状态,长时间未检测到。

当然,静态断言中的expression式必须是编译时常量。 它不能成为运行时间值。 对于运行时的值,你别无select,只能使用普通的assert

我用它来确保我对编译器行为,头文件,库文件,甚至我自己的代码都是正确的。 例如在这里我validation结构已被正确打包到预期的大小。

 struct LogicalBlockAddress { #pragma pack(push, 1) Uint32 logicalBlockNumber; Uint16 partitionReferenceNumber; #pragma pack(pop) }; BOOST_STATIC_ASSERT(sizeof(LogicalBlockAddress) == 6); 

在包装stdio.hfseek() ,我使用了enum Origin快捷方式,并检查这些快捷方式是否与由stdio.h定义的常量alignment

 uint64_t BasicFile::seek(int64_t offset, enum Origin origin) { BOOST_STATIC_ASSERT(SEEK_SET == Origin::SET); 

在编译时定义行为时,应该首选static_assert而不是在运行时(如上面给出的示例)。 不是这种情况的例子将包括参数和返回代码检查。

BOOST_STATIC_ASSERT是预C ++ 0xmacros,如果条件不满足,会生成非法代码。 意图是相同的,尽pipestatic_assert是标准化的,并且可以提供更好的编译器诊断。

BOOST_STATIC_ASSERT是一个用于static_assertfunction的跨平台包装器。

目前,我正在使用static_assert为了执行一个类的“概念”。

例:

 template <typename T, typename U> struct Type { BOOST_STATIC_ASSERT(boost::is_base_of<T, Interface>::value); BOOST_STATIC_ASSERT(std::numeric_limits<U>::is_integer); /* ... more code ... */ }; 

如果没有满足上述任何条件,将会导致编译时错误。

static_assert一个用途可能是确保结构(即与外部世界的接口,如networking或文件)的大小恰好与您所期望的相同。 这将会发现有人在结构中增加或修改了一个成员而没有意识到后果。 static_assert会提取并提醒用户。

这并不直接回答原来的问题,而是对如何在C ++ 11之前执行这些编译时检查做了一个有趣的研究。

现代C ++devise的第2章(第2.1节)由Andrei Alexanderscu实现了这样的编译时断言的想法

 template<int> struct CompileTimeError; template<> struct CompileTimeError<true> {}; #define STATIC_CHECK(expr, msg) \ { CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; } 

比较macrosSTATIC_CHECK()和static_assert()

 STATIC_CHECK(0, COMPILATION_FAILED); static_assert(0, "compilation failed"); 

在没有概念的情况下,可以使用static_assert进行简单和可读的编译时types检查,例如在模板中:

 template <class T> void MyFunc(T value) { static_assert(std::is_base_of<MyBase, T>::value, "T must be derived from MyBase"); // ... }