8

Problem

The following does not build because the message is not a string-literal.

template<typename T>
struct Foo
{ 
  Foo() 
  {
    static_assert( is_pod<T>::value, typeid(T).name() );
  }
};

Ultimately, I would like a failure message like "Bar must be a pod-type", if I try to compile Foo<Bar> fb;.

Is it possible to build this string during compile-time, as required by static_assert?

kfmfe04
  • 14,936
  • 14
  • 74
  • 140
  • Compiling a string at compile-time -- you should be able to do this with some dirty macro tricks or template magic. [See here](http://stackoverflow.com/q/6002594/183120) for something similar. – legends2k Jan 03 '14 at 13:48

2 Answers2

7

It's not possible to build the required string at compile time and to put it in the message, but this is usually not a problem in practice as the error message will contain the calling context and you can always create a wrapper for your static_assert which shows the type in the error message:

template< typename T >
void verify_pod()
{
    static_assert( std::is_pod<T>::value, "T is not a POD" );
}

yields

clang++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp:7:5: error: static_assert failed "T is not a POD"
    static_assert( std::is_pod<T>::value, "T is not a POD" );
    ^              ~~~~~~~~~~~~~~~~~~~~~
main.cpp:12:5: note: in instantiation of function template specialization 'verify_pod<std::basic_string<char> >' requested here
    verify_pod< std::string >();
    ^
1 error generated.

Note the note: ... where the wrapper with the type std::string (or here: std::basic_string<char>) is shown.

Live example (Clang)

For GCC, the error message is also very nice:

main.cpp: In instantiation of 'void verify_pod() [with T = std::basic_string<char>]':
main.cpp:12:31:   required from here
main.cpp:7:5: error: static assertion failed: T is not a POD
     static_assert( std::is_pod<T>::value, "T is not a POD" );
     ^

Live example (GCC)

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
  • Note that g++ propably won't yield such a nice error message. – arne Jan 03 '14 at 12:16
  • 2
    @arne Not true. Actually, GCC's error message is even nicer (IMHO). – Daniel Frey Jan 03 '14 at 12:18
  • We seem to have very different ideas of nice error messages. In your case it might look okay-ish, but if you have a lot of template-stuff going on, g++'s output becomes virtually unreadable imho. Your answer is correct nevertheless. – arne Jan 03 '14 at 12:28
  • 3
    I dunno, that looks fairly nice to me compared to some of the really ugly error messages I've seen. :) – Retired Ninja Jan 03 '14 at 12:31
3

Inside templates, you get what Daniel Frey's has explained. Outside templates, this isn't possible with static_assert alone but can be accomplished with the help of a macro and the stringification operator #:

#define VERIFY_POD(T) \
    static_assert(std::is_pod<T>::value, #T " must be a pod-type" );

For the type struct non_pod { virtual ~non_pod() {} }; with gcc 4.8.1, VERIFY_POD(non_pod) gives

main.cpp:4:2: error: static assertion failed: non_pod must be a pod-type
  static_assert(std::is_pod<T>::value, #T " must be a pod-type" );
  ^
main.cpp:15:2: note: in expansion of macro 'VERIFY_POD'
  VERIFY_POD(non_pod);

If you're like me and don't want to see the tokens #T " must be a pod-type" in the error message, then you can add an extra line to the macro definition:

#define VERIFY_POD(T) \
    static_assert(std::is_pod<T>::value, \
    #T "must be a pod-type" );

with this, the previous example yields:

main.cpp: In function 'int main()':
main.cpp:4:2: error: static assertion failed: non_pod must be a pod-type
  static_assert(std::is_pod<T>::value, \
  ^
main.cpp:14:2: note: in expansion of macro 'VERIFY_POD'
  VERIFY_POD(non_pod);
  ^

Of course, the exact look of the error message depends on the compiler. With clang 3.4 we get

main.cpp:14:5: error: static_assert failed "non_pod must be a pod-type"
    VERIFY_POD(non_pod);
    ^~~~~~~~~~~~~~~~~~~

main.cpp:3:23: note: expanded from macro 'VERIFY_POD'
#define VERIFY_POD(T) \
                      ^
1 error generated.
Community
  • 1
  • 1
Cassio Neri
  • 19,583
  • 7
  • 46
  • 68
  • 1
    I don't think this can work with templates as in the OP. I mean, it'll output the name of the template parameter, if I'm not mistaken. – dyp Jan 03 '14 at 13:32
  • @DyP Indeed, this works better outside templates. Inside templates it "works" the same way as in [Daniel Frey](http://stackoverflow.com/users/2073257/daniel-frey)'s [answer](http://stackoverflow.com/a/20903339/1137388). – Cassio Neri Jan 03 '14 at 13:39
  • @DyP I updated the post to clarify this point. Thanks. – Cassio Neri Jan 03 '14 at 13:42
  • *"Outside templates, this isn't possible with `static_assert` alone"* it works as well as inside templates ;) your solution does work *better* outside templates than just using a `static_assert`, +1 for that. – dyp Jan 03 '14 at 13:46
  • I think you can just print what has been written as the parameter, but note that this is *exactly* what you put in the `static_assert` is the first parameter. And if the static assert fails, this line, including what you have written is printed in the error message. – Daniel Frey Jan 03 '14 at 14:35