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