Распечатать имя шаблона во время компиляции - PullRequest
33 голосов
/ 22 марта 2012

При создании функции шаблона в C ++ существует простой способ, чтобы имя типа шаблона было представлено в виде строки?У меня есть простой тестовый пример, чтобы показать, что я пытаюсь сделать (обратите внимание, что указанный код не компилируется):

#include <stdio.h>
template <typename type>
type print(type *addr) 
{
  printf("type is: %s",type);
}

int main()
{
  int a;
  print(&a);
}

// Would like to print something like:
// type is: int

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

Причина, по которой я хочу сделать это, для некоторой отладки типа printf.У меня есть несколько потоков, работающих и GDB меняет поведение программы.Поэтому для некоторых вещей я хочу получить информацию о том, какие функции выполнялись.Это не так важно, поэтому, если решение слишком сложное, я бы пропустил добавление этой информации в свою функцию регистрации.Но если бы был простой способ сделать это, было бы полезно иметь информацию.

Ответы [ 7 ]

52 голосов
/ 16 мая 2015

Чтобы получить полезное имя времени компиляции:

Предположим, у вас есть неизвестный тип с именем 'T'.Вы можете заставить компилятор печатать его тип, используя его ужасно.Например:

typedef typename T::something_made_up X;

Сообщение об ошибке будет выглядеть следующим образом:

error: no type named 'something_made_up' in 'Wt::Dbo::ptr<trader::model::Candle>'

Бит после 'in' показывает тип.(Проверено только с помощью clang).

Другие способы его запуска:

bool x = T::nothing;   // error: no member named 'nothing' in 'Wt::Dbo::ptr<trader::model::Candle>'
using X = typename T::nothing;  // error: no type named 'nothing' in 'Wt::Dbo::ptr<trader::model::Candle>'

С C ++ 11 у вас уже может быть объект и использовать 'decltype' для получения его типатак что вы также можете запустить:

auto obj = creatSomeObject();
bool x = decltype(obj)::nothing; // (Where nothing is not a real member). 
21 голосов
/ 22 марта 2012

__PRETTY_FUNCTION__ должен решить вашу проблему (по крайней мере, во время выполнения)

Вывод программы ниже:

asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
!!!Hello World!!!

Если вам действительно нужно имя типастроку, вы можете взломать это (используя snprintf вместо printf) и вытянуть подстроку после '=' и перед ']'.

#include <iostream>
using namespace std;

template<typename type>
class test
{
public:
test()
{
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
}
};

template<typename type>
void tempFunction()
{
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
}

int main() {
    test<int> test;

    tempFunction<bool>();
    cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
    return 0;
}
11 голосов
/ 22 марта 2012

Поскольку вы сказали, что вам это понадобится для целей отладки, возможно, решение во время выполнения также приемлемо.И вы пометили это как g ++, так что вы не хотите соответствовать стандарту.

Вот что это значит:

#include <cxxabi.h> // the libstdc++ used by g++ does contain this header

template <typename type>
void print(const type *addr) // you wanted a pointer
{
  char * name = abi::__cxa_demangle(typeid(*addr).name(), 0, 0, NULL);
  printf("type is: %s\n", name);
  free(name);
}

print(new unsigned long);    // prints "type is: unsigned long"
print(new std::vector<int>); // prints "type is: std::vector<int, std::allocator<int> >"

РЕДАКТИРОВАТЬ: исправлена ​​утечка памятиСпасибо Джесси.

6 голосов
/ 26 февраля 2015

Есть библиотека Boost.TypeIndex.

Подробнее см. Boost :: typeindex :: type_id.

Это очень простое в использовании, кроссплатформенное и реальное решение типа компиляции. Также это работает, даже если нет RTTI. Также большинство компиляторов поддерживаются из коробки.

1 голос
/ 21 сентября 2017

Другое решение времени компиляции, аналогичное предоставленному matiu , но, возможно, немного более наглядное - использовать static_assert, заключенный в небольшую вспомогательную функцию.

template<typename T>
void print_type_in_compilation_error(T&&)
{
    static_assert(std::is_same<T, int>::value && !std::is_same<T, int>::value, "Compilation failed because you wanted to read the type. See below");
}
// usage:
int I;
print_type_in_compilation_error(I);

Выше приведено хорошее сообщение об ошибке (проверено в MSVC и Clang), как и в другом ответе, но код, ИМХО, лучше понять.

0 голосов
/ 29 октября 2018

Как прокомментировали @chris и @Philipp, если вам действительно не нужно имя во время компиляции, вы можете использовать typeid(type).name() после включения <typeinfo>.

0 голосов
/ 22 марта 2012

если у вас есть известный набор используемых типов для создания экземпляра шаблона, мы можем использовать подход, описанный в этой старой теме: stackoverflow.com / questions / 1055452

...