2

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:

  • g++: no matching function for call to ‘CompileTimeChecker<false>::CompileTimeChecker(main()::ERROR_MessageNull)
  • clang++: no matching conversion for functional-style cast from 'ERROR_MessageNull' to 'CompileTimeChecker<(0 != 0)>'
3
  • 5
    Why not static_assert? Commented Jul 23, 2019 at 10:31
  • 1
    Also, it should be CompileTimeChecker<(expr)>, not CompileTimeChecker<(expr != 0)>, because this is a macro. Commented Jul 23, 2019 at 10:38
  • 1
    @Yksisarvinen: Mostly because "Modern C++ Design" is no longer modern. It predates C++11 and static_assert. Commented Jul 23, 2019 at 14:12

1 Answer 1

5

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Yes, and also it's specifically allowed to have both a struct and a function with the same name in the same scope, for header compatibility with C.
The parentheses didn't fix it for me because function((a)) is equal to function(a). But you are right about the function/constructor ambiguity. Writing CompileTimeChecker<expr>(Type{}); fixed it for me (i.e. using uniform initialization). Can you update your answer?
@L.F. CompileTimeChecker<expr>((Type())); is not working for me.
@image I am wrong. I confused this case with another case of most vexing parse. I have updated the answer. Hope it doesn't vex us again!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.