什么是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 int
types,编译将会失败,从而引起开发人员注意代码中有问题的部分,并build议他们重新执行或重新检查它。
另一个例子,你可能想要传递一个整数值作为一个void *
指向一个函数(一个黑客,但有时有用),你想确保整数值将适合指针
int i; static_assert(sizeof(void *) >= sizeof i); foo((void *) i);
您可能想要资产该char
types签名
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.h
的fseek()
,我使用了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_assert
function的跨平台包装器。
目前,我正在使用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"); // ... }