Напечатать имя типа во время компиляции без прерывания компиляции?

В этом вопросе:

Печать имени типа шаблона во время компиляции

у нас есть несколько предложений относительно того, как заставить типичные компиляторы C++ печатать имя типа во время компиляции. Однако они полагаются на инициирование ошибки компиляции.

Мой вопрос: могу ли я заставить компилятор C++ печатать имя типа без остановки компиляции?

В общем, ответ «вероятно, нет», потому что действующая программа может быть скомпилирована в свой целевой объект, ничего нигде не печатая, поэтому я спрашиваю конкретно о GCC и clang с возможным использованием директив препроцессора, встроенных компиляторов или любого другого компилятора. - конкретный трюк.

Примечания:

  • Очевидно, что проблема заключается в печати типов за операторами using/typedef, значениями параметров шаблона, вариативными шаблонами и т. д. Если тип доступен явно, вы можете просто использовать что-то вроде #message "my type is unsigned long long" (как предложил @NutCracker). Но вопрос не в этом.
  • Ответы, основанные на C++ 11 или более ранних версиях, предпочтительнее, чем требующие C++ 14/17/20.

person einpoklum    schedule 13.02.2020    source источник
comment
Меня больше интересует, зачем вам это нужно? Какую проблему это должно решить?   -  person Some programmer dude    schedule 13.02.2020
comment
@Someprogrammerdude: инструмент отладки TBH. Я просто хочу, чтобы некоторые из них были напечатаны до того, как я столкнусь с некоторыми ошибками, вместо того, чтобы преждевременно прерывать компиляцию.   -  person einpoklum    schedule 13.02.2020
comment
@Someprogrammerdude: Еще одна мотивация - это.   -  person einpoklum    schedule 13.02.2020


Ответы (3)


gcc и clang предлагают некоторый интерфейс для использования собственных плагинов, которые могут делать почти все на разных этапах от синтаксического анализа до генерации кода.

Интерфейсы зависят от компилятора, и этот плагин для gcc нельзя использовать для clang или наоборот.

Документация обширна, и здесь нет возможности вдаваться в подробности, поэтому я укажу вам только на документы от gcc и clang:

плагин gcc плагин clang

person Klaus    schedule 13.02.2020
comment
Я думаю, вы имеете в виду специфичный для компилятора или идиосинкразический, а не проприетарный. - person einpoklum; 13.02.2020
comment
См. эту страницу в Википедии. - person einpoklum; 13.02.2020
comment
@einpoklum: Спасибо за подсказку! Опять чему-то научился... :-) - person Klaus; 14.02.2020

Следующий механизм связан с @JonathanWakely и специфичен для GCC:

int i;

template <typename T>
[[gnu::warning("your type here")]]
bool print_type() { return true; }

bool b = print_type<decltype(i)>();

Это дает вам:

<source>:In function 'void __static_initialization_and_destruction_0(int, int)':
<source>:7:33: warning: call to 'print_type<int>' declared with attribute warning: your
type here [-Wattribute-warning]
    7 | bool b = print_type<decltype(i)>();
      |          ~~~~~~~~~~~~~~~~~~~~~~~^~

Посмотрите, как он работает над Godbolt.

person einpoklum    schedule 14.02.2020

В c++17 мы можем злоупотреблять атрибутом [[deprecated]], чтобы заставить компилятор выдать предупреждение, содержащее нужный параметр шаблона:

template<typename T>
[[deprecated]] inline constexpr void print_type(T&& t, const char* msg=nullptr){}

print_type(999, "I just want to know the type here...");

Фрагмент выше выведет следующее предупреждение с помощью gcc:

<source>:32:59: warning: 'constexpr void print_type(T&&, const char*) [with T = int]' is deprecated [-Wdeprecated-declarations]
     print_type(999, "I just want to know the type here...");

В отличие от принятого ответа, это будет работать с каждым компилятором, совместимым с С++ 17. Обратите внимание, что вам нужно будет включить \W3` на MSVC.

Мы можем даже пойти дальше и определить статический макрос assert, который будет печатать тип тогда и только тогда, когда он терпит неудачу.

template<bool b, typename T>
inline constexpr bool print_type_if_false(T&& t) {
    if constexpr (!b)
        print_type(std::forward<T>(t));
    return b;
}

// Some nice static assert that will print the type if it fails.
#define STATIC_ASSERT(x,condition, msg) static_assert(print_type_if_false<condition>(x), msg);

Вот живой пример.

person florestan    schedule 18.01.2021
comment
1. Это аккуратно, спасибо. 2. Зачем вообще передавать сообщение в print_type_if_false? - person einpoklum; 18.01.2021
comment
@einpoklum Ты прав, это не имеет особого смысла ... Я это исправлю. - person florestan; 18.01.2021