Is it possible to print a variable's type in standard C++?

前端 未结 21 1918
南笙
南笙 2020-11-22 01:41

For example:

int a = 12;
cout << typeof(a) << endl;

Expected output:

int
21条回答
  •  醉梦人生
    2020-11-22 02:13

    Another take on @康桓瑋's answer (originally ), making less assumptions about the prefix and suffix specifics, and inspired by @Val's answer - but without polluting the global namespace; without any conditions; and hopefully easier to read.

    The popular compilers provide a macro with the current function's signature. Now, functions are templatable; so the signature contains the template arguments. So, the basic approach is: Given a type, be in a function with that type as a template argument.

    Unfortunately, the type name is wrapped in text describing the function, which is different between compilers. For example, with GCC, the signature of template int foo() with type double is: int foo() [T = double].

    So, how do you get rid of the wrapper text? @HowardHinnant's solution is the shortest and most "direct": Just use per-compiler magic numbers to remove a prefix and a suffix. But obviously, that's very brittle; and nobody likes magic numbers in their code. Instead, you get the macro value for a type with a known name, you can determine what prefix and suffix constitute the wrapping.

    #include 
    
    template  constexpr std::string_view type_name();
    
    template <>
    constexpr std::string_view type_name()
    { return "void"; }
    
    namespace detail {
    
    using type_name_prober = void;
    
    template 
    constexpr std::string_view wrapped_type_name() 
    {
    #ifdef __clang__
        return __PRETTY_FUNCTION__;
    #elif defined(__GNUC__)
        return __PRETTY_FUNCTION__;
    #elif defined(_MSC_VER)
        return __FUNCSIG__;
    #else
    #error "Unsupported compiler"
    #endif
    }
    
    constexpr std::size_t wrapped_type_name_prefix_length() { 
        return wrapped_type_name().find(type_name()); 
    }
    
    constexpr std::size_t wrapped_type_name_suffix_length() { 
        return wrapped_type_name().length() 
            - wrapped_type_name_prefix_length() 
            - type_name().length();
    }
    
    } // namespace detail
    
    template 
    constexpr std::string_view type_name() {
        constexpr auto wrapped_name = detail::wrapped_type_name();
        constexpr auto prefix_length = detail::wrapped_type_name_prefix_length();
        constexpr auto suffix_length = detail::wrapped_type_name_suffix_length();
        constexpr auto type_name_length = wrapped_name.length() - prefix_length - suffix_length;
        return wrapped_name.substr(prefix_length, type_name_length);
    }
    

    See it on GodBolt. This should be working with MSVC as well.

提交回复
热议问题