Can I obtain C++ type names in a constexpr way?

前端 未结 2 1918
悲&欢浪女
悲&欢浪女 2020-12-03 01:13

I would like to use the name of a type at compile time. For example, suppose I\'ve written:

constexpr size_t my_strlen(const char* s)
{
        const char* c         


        
相关标签:
2条回答
  • 2020-12-03 01:32

    Well, you could, sort of, but probably not quite portable:

    struct string_view
    {
        char const* data;
        std::size_t size;
    };
    
    inline std::ostream& operator<<(std::ostream& o, string_view const& s)
    {
        return o.write(s.data, s.size);
    }
    
    template<class T>
    constexpr string_view get_name()
    {
        char const* p = __PRETTY_FUNCTION__;
        while (*p++ != '=');
        for (; *p == ' '; ++p);
        char const* p2 = p;
        int count = 1;
        for (;;++p2)
        {
            switch (*p2)
            {
            case '[':
                ++count;
                break;
            case ']':
                --count;
                if (!count)
                    return {p, std::size_t(p2 - p)};
            }
        }
        return {};
    }
    

    And you can define your desired type_name_length as:

    template <typename T>
    constexpr auto type_name_length = get_name<T>().size;
    

    DEMO (works for clang & g++)

    0 讨论(0)
  • 2020-12-03 01:41

    (Based on @melak47's gist and using C++17):

    #using <string_view>
    // and if it's not C++17, take the GSL implementation or just roll your own struct - 
    // you only need to implement 3 or 4 methods here.
    
    namespace detail {
    
    template<typename T>
    constexpr const char* templated_function_name_getter() {
    #if defined(__GNUC__) || defined(__clang__)
        return __PRETTY_FUNCTION__;
    #elif defined(_MSC_VER)
        return __FUNCSIG__;
    #else
    #error unsupported compiler (only GCC, clang and MSVC are supported)
    #endif
    }
    
    } // namespace detail
    
    template<typename T>
    constexpr std::string_view type_name() {
    
        constexpr std::string_view funcsig =  detail::templated_function_name_getter<T>();
    
        // Note: The "magic numbers" below 
    
        #if defined(__GNUC__) || defined(__clang__)
        constexpr auto start_bit = std::string_view{"T = "};
        constexpr auto end_bit = std::string_view{"]"};
        #elif defined(_MSC_VER)
        constexpr auto start_bit = std::string_view{"detail::templated_function_name_getter<"};
        constexpr auto end_bit = std::string_view{">("};
        #else
        #error unsupported compiler (only GCC, clang and MSVC are supported)
        #endif
    
        constexpr auto start = funcsig.find(start_bit);
        constexpr auto end = funcsig.rfind(end_bit);
        static_assert(
            start != funcsig.npos and end != funcsig.npos and end > start, 
            "Failed parsing the __PRETTY_FUNCTION__/__FUNCSIG__ string");
        }
        return funcsig.substr(start + start_bit.size(), end - start - start_bit.size());
    }
    

    Note: There's now a nicer version of this approach implemented here.

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