2013-08-21 2 views
5

Есть ли простой способ заставить компиляторы показать мне тип, выведенный для параметра шаблона? Например, приКак я могу увидеть тип, выводимый для параметра типа шаблона?

template<typename T> 
void f(T&& parameter); 

const volatile int * const pInt = nullptr; 
f(pInt); 

я мог бы увидеть, какой тип выводится для T в вызове f. (Я думаю, что это const volatile int *&, но я не уверен.) Или данный

template<typename T> 
void f(T parameter); 

int numbers[] = { 5, 4, 3, 2, 1 }; 
f(numbers); 

я мог бы узнать, если мое предположение, что T выводится как в вызове int* к f правильно.

Если есть стороннее решение библиотеки (например, от Boost), мне было бы интересно узнать об этом, но я также хотел бы знать, есть ли простой способ заставить диагностику компиляции, которая включала бы выведенный тип.

+5

Вы хотите это во время компиляции или во время выполнения? последнее можно сделать с помощью '#include ' и 'typeid (T) .name()' – TemplateRex

+0

'std :: is_same :: value'? – Rapptz

+0

@TemplateRex: Я бы хотел видеть тип во время компиляции. – KnowItAllWannabe

ответ

2

Чтобы заставить компилятор показать вам тип переменной (возможно, в раунде);

T parameter; 
.... 
void f(int x); 
... 
f(parameter); 

компилятор должен жаловаться, что «T» не может быть преобразован в целом, при условии, что он на самом деле не может. Решение времени

+0

Это интересная идея, но, по крайней мере, с gcc 4.8.1 и MSVC 12, у нее есть недостатки. В первом примере gcc сообщает тип дважды: один раз как 'const volatile int * const &&&' (да, с тремя амперсандами!), Один раз как 'const volatile int * const'. MSVC также сообщает тип дважды, один раз, как 'volatile const int * const', один раз как' volatile const int * const & '. – KnowItAllWannabe

11

Ссылки:

На моей платформе (OS X), я могу получить компоновщик, чтобы дать мне эту информацию, просто сделав короткую программу, которая является полной, минус определение функции I» м интересно:

template<typename T> 
void f(T&& parameter); // purposefully not defined 

int 
main() 
{ 
    const volatile int * const pInt = nullptr; 
    f(pInt); 
} 

Undefined symbols for architecture x86_64: 
    "void f<int const volatile* const&>(int const volatile* const&&&)", referenced from: 
     _main in test-9ncEvm.o 
ld: symbol(s) not found for architecture x86_64 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 

по общему признанию я получить «тройной справочник», который должен быть интерпретирован как именующие ссылки (из-за разрушение ссылки), и является декодирование ошибки (возможно, можно получить, что неподвижным).


Run решение Время:

Я держу type_name<T>() функцию удобно для такого рода вещи. Полностью переносная, возможно, но не оптимальная для меня. Вот оно:

#include <type_traits> 
#include <typeinfo> 
#include <string> 

template <typename T> 
std::string 
type_name() 
{ 
    typedef typename std::remove_reference<T>::type TR; 
    std::string r = typeid(TR).name(); 
    if (std::is_const<TR>::value) 
     r += " const"; 
    if (std::is_volatile<TR>::value) 
     r += " volatile"; 
    if (std::is_lvalue_reference<T>::value) 
     r += "&"; 
    else if (std::is_rvalue_reference<T>::value) 
     r += "&&"; 
    return r; 
} 

я могу использовать его как:

#include <iostream> 

template<typename T> 
void f(T&& parameter) 
{ 
    std::cout << type_name<T>() << '\n'; 
} 

int 
main() 
{ 
    const volatile int * const pInt = nullptr; 
    f(pInt); 
} 

, который для меня печатает:

PVKi const& 

Это не очень дружественный выход. Ваш опыт может быть лучше. Моя платформа ABI основана на Itanium ABI. И это ABI включает в себя эту функцию:

namespace abi 
{ 
    extern "C" 
    char* 
    __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status); 
} 

я могу использовать это demangle символы C++ в читаемом виде.Обновленный type_name<T>() воспользоваться это:

#include <type_traits> 
#include <typeinfo> 
#include <string> 
#include <memory> 
#include <cstdlib> 
#include <cxxabi.h> 

template <typename T> 
std::string 
type_name() 
{ 
    typedef typename std::remove_reference<T>::type TR; 
    std::unique_ptr<char, void(*)(void*)> own 
     (
      abi::__cxa_demangle(typeid(TR).name(), nullptr, nullptr, nullptr), 
      std::free 
     ); 
    std::string r = own != nullptr ? own.get() : typeid(TR).name(); 
    if (std::is_const<TR>::value) 
     r += " const"; 
    if (std::is_volatile<TR>::value) 
     r += " volatile"; 
    if (std::is_lvalue_reference<T>::value) 
     r += "&"; 
    else if (std::is_rvalue_reference<T>::value) 
     r += "&&"; 
    return r; 
} 

А теперь предыдущего main() распечатывает:

int const volatile* const& 
+0

Это полезно, спасибо. Я также обнаружил, что подобная информация доступна через '__PRETTY_FUNCTION__' под gcc и clang и под' __FUNCSIG__' под MSVC. Они производят строки, поэтому они приводят к решениям времени исполнения. – KnowItAllWannabe

+0

@KnowItAllWannabe, если вы не используете его, например. 'static_assert' – sehe

+0

@sehe: Увы,' __PRETTY_FUNCTION__' действует как переменная, а не строковый литерал, поэтому ее нельзя использовать внутри 'static_assert'. – KnowItAllWannabe

6

Я попробовал следующее с г ++ 4.7.2 и лязгом ++ 3.4 (магистральных 184647); они оба дают

ошибка времени компиляции и сообщение об ошибке содержат выведенный тип.

У меня нет доступа к MSVC 12, пожалуйста, проверьте, что происходит, и обеспечивайте обратную связь.

#include <string> 

template <typename T> 
struct deduced_type; 


template<typename T> 
void f(T&&) { 

    deduced_type<T>::show; 
} 

int main() { 

    f(std::string()); // rvalue string 

    std::string lvalue; 

    f(lvalue); 

    const volatile int * const pInt = nullptr; 

    f(pInt); 
} 

сообщения об ошибках: г ++ 4.7.2

ошибка: неполный тип deduced_type<std::basic_string<char> > используется в гнездовом имени спецификатор
ошибки: неполный тип deduced_type<std::basic_string<char>&> используется в гнездовом имени спецификатор
ошибки: неполный тип deduced_type<const volatile int* const&> используется в вложенное имя спецификатор

и лязг ++

Эрро г: неявная конкретизация неопределенной матрицы deduced_type<std::basic_string<char> >
ошибка: неявная конкретизация неопределенной матрицы deduced_type<std::basic_string<char> &>
ошибка: неявная конкретизация неопределенной матрицы deduced_type<const volatile int *const &>

Примечания/информационные сообщения также содержат тип f с обеими компиляторами, например

В конкретизации void f(T&&) [with T = std::basic_string<char>]

Это стыковой некрасиво, но работает.

+0

+1 Да, я согласен. Это тоже работает. –

+0

@HowardHinnant Спасибо за проверку. (Я ответил на ваш ответ 3 часа назад.) – Ali

Смежные вопросы