Подтвердить что ты не робот

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

При создании функции шаблона в 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 меняет поведение программы. Поэтому для некоторых вещей я хочу получить информацию о том, какие функции выполнялись. Это не слишком важно, поэтому, если решение слишком сложное, я бы пропустил добавление этой информации в свою функцию регистрации. Но если бы существовал простой способ сделать это, была бы полезна информация.

4b9b3361

Ответ 1

__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;
}

Ответ 2

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

Предположим, что у вас есть неизвестный тип с именем "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>'

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

auto obj = creatSomeObject();
bool x = decltype(obj)::nothing; // (Where nothing is not a real member). 

Ответ 3

Поскольку вы сказали, что вам это понадобится для целей отладки, возможно, также приемлемо решение во время выполнения. И вы пометили это как 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);
  delete name;
}

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

ОБНОВЛЕНИЕ: исправлена утечка памяти. Спасибо Джесси.

Ответ 4

Существует библиотека Boost.TypeIndex.

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

Это очень простой в использовании, кросс-платформенный и является реальным компиляционным решением. Также он работает, даже если RTTI не доступен. Кроме того, большинство компиляторов поддерживается из коробки.

Ответ 5

Другое решение для времени компиляции, аналогичное тому, которое предоставляется 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), как и в другом ответе, но код лучше понять, чем IMHO.

Ответ 6

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

Ответ 7

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