Как внедрить имя типа в виде строки в static_assert()?

Проблема

Следующее не создается, потому что сообщение не является строковым литералом.

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

В конечном счете, я бы хотел, чтобы сообщение об ошибке типа «Bar должно быть типа pod», если я попытаюсь скомпилировать Foo<Bar> fb;.

Можно ли создать эту строку во время компиляции, как того требует static_assert?


person kfmfe04    schedule 03.01.2014    source источник
comment
Компиляция строки во время компиляции - вы должны быть в состоянии сделать это с помощью некоторых грязных трюков с макросами или магии шаблонов. Посмотрите здесь что-то подобное.   -  person legends2k    schedule 03.01.2014


Ответы (2)


Невозможно построить требуемую строку во время компиляции и поместить ее в сообщение, но на практике это обычно не проблема, поскольку сообщение об ошибке будет содержать контекст вызова, и вы всегда можете создать оболочку для вашего static_assert, которая показывает введите сообщение об ошибке:

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

урожаи

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: ..., где показана оболочка с типом std::string (или здесь: std::basic_string<char>).

Живой пример (Clang)

Для GCC сообщение об ошибке также очень приятное:

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" );
     ^

Живой пример (GCC)

person Daniel Frey    schedule 03.01.2014
comment
Обратите внимание, что g++, вероятно, не выдаст такого приятного сообщения об ошибке. - person arne; 03.01.2014
comment
@арне Неправда. На самом деле сообщение об ошибке GCC даже лучше (ИМХО). - person Daniel Frey; 03.01.2014
comment
Кажется, у нас очень разные представления о красивых сообщениях об ошибках. В вашем случае это может выглядеть нормально, но если у вас много шаблонов, вывод g++ становится практически нечитаемым imho. Тем не менее ваш ответ правильный. - person arne; 03.01.2014
comment
Не знаю, мне это кажется довольно приятным по сравнению с некоторыми действительно уродливыми сообщениями об ошибках, которые я видел. :) - person Retired Ninja; 03.01.2014

Внутри шаблонов вы получаете то, что Дэниел Фрей имеет объяснено. Вне шаблонов это невозможно только с помощью static_assert, но это можно сделать с помощью макроса и оператора строкового преобразования #:

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

Для типа struct non_pod { virtual ~non_pod() {} }; с gcc 4.8.1 VERIFY_POD(non_pod) дает

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

Если вы похожи на меня и не хотите видеть токены #T " must be a pod-type" в сообщении об ошибке, вы можете добавить дополнительную строку в определение макроса:

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

при этом предыдущий пример дает:

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

Конечно, точный вид сообщения об ошибке зависит от компилятора. С clang 3.4 получаем

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.
person Cassio Neri    schedule 03.01.2014
comment
Я не думаю, что это может работать с шаблонами, как в ОП. Я имею в виду, что он выведет имя параметра шаблона, если я не ошибаюсь. - person dyp; 03.01.2014
comment
@DyP Действительно, это лучше работает вне шаблонов. Внутри шаблонов это работает так же, как в файле Дэниела Фрея ответить. - person Cassio Neri; 03.01.2014
comment
@DyP Я обновил пост, чтобы прояснить этот момент. Спасибо. - person Cassio Neri; 03.01.2014
comment
Вне шаблонов это невозможно только с static_assert, он работает так же хорошо, как и внутри шаблонов;) ваше решение работает лучше вне шаблонов, чем просто использование static_assert, +1 для тот. - person dyp; 03.01.2014
comment
Я думаю, вы можете просто напечатать то, что было написано в качестве параметра, но обратите внимание, что это точно то, что вы поместили в static_assert — это первый параметр. И если статическое утверждение терпит неудачу, эта строка, включая то, что вы написали, печатается в сообщении об ошибке. - person Daniel Frey; 03.01.2014