编译时断言不可靠?

Compile Time Assertion is Unreliable?

我正在阅读本书的第一章 "Modern C++ Design"。特别是编译时断言。我对以下代码有一些问题:

template<bool> struct CompileTimeChecker
{
  CompileTimeChecker(...) {}
};

template<> struct CompileTimeChecker<false> {};

#define STATIC_CHECK(expr, msg)\
{\
  struct ERROR_##msg {ERROR_##msg() {}};\
  CompileTimeChecker<((expr) != 0)>(ERROR_##msg());\
}

int main()
{
  STATIC_CHECK(0, MessageNull);
  STATIC_CHECK(1, MessageOne);
}

这不会引发 g++ 7.4.0 和 clang++ 6.0.0 的编译时错误。但是,以下代码确实会引发错误(正如预期的那样):

template<bool> struct CompileTimeChecker
{
  CompileTimeChecker(...) {}
};

template<> struct CompileTimeChecker<false> {};

#define STATIC_CHECK(expr, msg)\
{\
  struct ERROR_##msg {ERROR_##msg(int i) {i;}};\
  CompileTimeChecker<((expr) != 0)>(ERROR_##msg(0));\
}

int main()
{
  STATIC_CHECK(0, MessageNull);
  STATIC_CHECK(1, MessageOne);
}

第二个代码的唯一区别是使用带参数的构造函数。


两种情况下的预期错误消息是:

这被称为最令人烦恼的解析。以下声明:

CompileTimeChecker<expr>(Type());

相当于

CompileTimeChecker<expr> Type();

它声明了一个名为 Type 的函数。您可以使用 = 初始化形式解决此问题:

CompileTimeChecker<expr> var = Type();

这样,就不能解释为声明了。自 C++11 起,您还可以使用 {} 初始化。另一方面,

CompileTimeChecker<expr>(Type(0));

是一个根据需要创建对象的表达式语句,因为 Type(0) 不可能声明函数。

自 C++11 起,只需使用 static_assert.