image357
image357

Reputation: 471

Compile Time Assertion is Unreliable?

I am going through the first chapters of the book "Modern C++ Design". In particular, compile time assertions. I have some problem with the following code:

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);
}

This doesn't raise a compile time error for g++ 7.4.0 and clang++ 6.0.0. However, the following code does raise an error (as expected):

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);
}

The only difference in the second code is the usage of a constructor with parameters.


The expected error message in both cases is:

Upvotes: 2

Views: 143

Answers (1)

L. F.
L. F.

Reputation: 20569

This is called the most vexing parse. The following statement:

CompileTimeChecker<expr>(Type());

is equivalent to

CompileTimeChecker<expr> Type();

which declares a function named Type. You can work around the issue by using the = form of initialization:

CompileTimeChecker<expr> var = Type();

This way, it cannot be interpreted as a declaration. You can also use the {} initialization since C++11. On the other hand,

CompileTimeChecker<expr>(Type(0));

is an expression statement that creates an object as desired because Type(0) cannot possibly declare a function.

Since C++11, just use static_assert.

Upvotes: 5

Related Questions