Print template typename at compile time

后端 未结 6 1169
予麋鹿
予麋鹿 2020-12-08 09:41

When creating a template function in C++ is there a simple way to have the typename of the template represented as a string? I have a simple test case to show what I\'m try

相关标签:
6条回答
  • 2020-12-08 10:04

    Since you have said you would need this for debugging purpose, maybe a runtime solution is also acceptable. And you have tagged this as g++ so you don't want to be standard conform.

    Here is what that means:

    #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> >"
    

    EDIT: corrected the memory leak. Thx to Jesse.

    0 讨论(0)
  • 2020-12-08 10:05

    To get a useful compile time name:

    Supposing you have some unknown type named 'T'. You can get the compiler to print it's type by using it horribly. For example:

    typedef typename T::something_made_up X;
    

    The error message will be like:

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

    The bit after 'in' shows the type. (Only tested with clang).

    Other ways of triggering it:

    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>'
    

    With C++11, you may already have an object and use 'decltype' to get its type, so you can also run:

    auto obj = creatSomeObject();
    bool x = decltype(obj)::nothing; // (Where nothing is not a real member). 
    
    0 讨论(0)
  • 2020-12-08 10:10

    Another compile time solution, similar to the one provided by matiu, but perhaps a little more descriptive would be to use a static_assert wrapped in a little helper function:

    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 know the type; see below:");
    }
    
    // usage:
    int I;
    print_type_in_compilation_error(I);
    

    The above will give you a nice error message (tested in MSVC and Clang), as in the other answer, but the code is easier to understand in my opinion.

    0 讨论(0)
  • 2020-12-08 10:14

    __PRETTY_FUNCTION__ should solve your problem (at run time at least)

    The output to the program below is:

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

    If you really, really, need the typename as a string, you could hack this (using snprintf instead of printf) and pull the substring after '=' and before ']'.

    #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 讨论(0)
  • 2020-12-08 10:15

    if you have a known set of types used instantiate the template we can use the approach described in this older thread: stackoverflow.com/questions/1055452

    0 讨论(0)
  • 2020-12-08 10:19

    There is Boost.TypeIndex library.

    See boost::typeindex::type_id for details.

    It is very-easy-to-use, cross-platform and is real compile-type solution. Also it works as well even if no RTTI available. Also most of compilers are supported from the box.

    0 讨论(0)
提交回复
热议问题