2012-03-21 2 views
28

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

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

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

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

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

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

+2

Попробуйте 'typeid (type) .name()' после включения chris

+0

вам это нужно во время компиляции? в противном случае 'typeid (type) .name()' может помочь. – Philipp

+0

Ничего, не видел время компиляции, но если вы его печатаете, я уверен, что вы можете понять это во время выполнения. – chris

ответ

21

__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!!! 

Если вы действительно, действительно, нужно TypeName как строка, вы могли бы взломать это (с помощью 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; 
} 
+0

Не компилируется на VS15. – shinzou

+2

@kuhaku Он будет компилироваться только в том случае, если вы используете компилятор, который поддерживает __PRETTY_FUNCTION__. [Просмотрите этот ответ, чтобы узнать подробности о __PRETTY_FUNCTION__] (http://stackoverflow.com/questions/4384765/whats-the-difference-between-pretty-function-function-func). Также [эта ссылка] (https://msdn.microsoft.com/library/b0084kay.aspx) покажет вам, какие макросы Windows могут использоваться для выполнения одной и той же вещи. Я подозреваю, что __func__ будет работать, но не попытался подтвердить. Я исключительно использую GCC, поэтому у меня нет среды для подтверждения. –

+0

Примечание: __PRETTY_FUNCTION__ должно быть \ _ \ _ PRETTY_FUNCTION \ _ \ _ и __func__ должно быть \ _ \ _ func \ _ \ _ –

11

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

EDIT: исправлена ​​утечка памяти. Тх к Джесси.

+0

Это не работает во время компиляции, он просто распечатывает имя с запятой – 111111

+0

Просто имейте в виду, что вы пропускаете память, поскольку 'malloc' вызывается с помощью [__cxa_demangle] (http://gcc.gnu.org/onlinedocs/libstdc++ /libstdc++-html-USERS-4.3/a01696.html). –

+0

благодарит, что решение для выполнения работает для того, что мне нужно. –

0

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

6

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

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

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

+0

Обратите внимание, что это доступно только для 'Boost> = 1.56.0'. – BenC

+0

Вы правы, но все же очень-очень просты в использовании, и это реальное решение для компиляции. И он работает, даже если информация RTTI недоступна. Кроме того, большинство компиляторов поддерживается из коробки. – Andrey

+0

Абсолютно, отсюда мой +1. Но следующей необходимой мне информацией была минимальная версия Boost, поскольку дистрибутивы, поставляющие более старые версии Boost, могут не иметь доступной библиотеки (например, Ubuntu 12.04), а это значит, что вам нужно будет вернуться к другим решениям, если «Boost <1.56 .0' обнаружено. Тем не менее, дополнительная информация, которую вы добавили, заслуживает того, чтобы быть в вашем ответе. – BenC

34

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

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

typedef typename T::something_made_up X; 

Сообщение об ошибке будет, как:

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

бит после того, как 'в' показывает тип. (Только тестирование с 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). 
+1

Это действительно помогает печатать имена типов во время компиляции, когда у вас есть код, который не компилируется! –

+2

Единственный ответ, чтобы ответить на вопрос! –

+1

Работает отлично с 'gcc' тоже. – cartoonist

0

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