我可以以constexpr方式获取C ++类型名称吗?

时间:2016-03-11 13:06:24

标签: c++ reflection c++14 constexpr compile-time

我想在编译时使用类型的名称。例如,假设我写了:

constexpr size_t my_strlen(const char* s)
{
        const char* cp = s;
        while(*cp != '\0') { cp++; };
        return cp - s;
}

现在我想要:

template <typename T>
constexpr auto type_name_length = my_strlen(typeid(T).name());

但是,唉,typeid(T).name()只是const char*,而不是constexpr ......还有其他一些方法可以获得类型的名称吗?

3 个答案:

答案 0 :(得分:64)

嗯,你可以,但可能不太便携:

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 {};
}

您可以将所需的type_name_length定义为:

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

DEMO(适用于clang&amp; g ++)

答案 1 :(得分:0)

(基于@ melak47的gist并使用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());
}

答案 2 :(得分:-1)

可以在模板中使用的替代答案,现在它可以与 g++ 和 clang++ 和 msvc 一起运行。

根据上面的@einpoklum 答案修改:https://stackoverflow.com/a/56600402/12529885

 Navigator.pushReplacementNamed(context, '/root');

注意:

Clang++ 中的全名:#include <iostream> #include <string_view> template<typename T> struct TypeName { constexpr static std::string_view fullname_intern() { #if defined(__clang__) || defined(__GNUC__) return __PRETTY_FUNCTION__; #elif defined(_MSC_VER) return __FUNCSIG__; #else #error "Unsupported compiler" #endif } constexpr static std::string_view name() { size_t prefix_len = TypeName<void>::fullname_intern().find("void"); size_t multiple = TypeName<void>::fullname_intern().size() - TypeName<int>::fullname_intern().size(); size_t dummy_len = TypeName<void>::fullname_intern().size() - 4*multiple; size_t target_len = (fullname_intern().size() - dummy_len)/multiple; std::string_view rv = fullname_intern().substr(prefix_len, target_len); if (rv.rfind(' ') == rv.npos) return rv; return rv.substr(rv.rfind(' ')+1); } using type = T; constexpr static std::string_view value = name(); }; namespace s1 { class MyClass; } //Both MSVC, G++ and Clang++ have passed test. int main () { static_assert(TypeName<s1::MyClass>::value == "s1::MyClass"); std::cout<<"FULLNAME> "<<TypeName<void>::fullname_intern()<<std::endl; std::cout<<"TYPETEST> '"<<TypeName<s1::MyClass>::value<<"' == 's1::MyClass'"<<std::endl; return 0; }

G++ 中的全名:static std::string_view TypeName<void>::fullname_intern() [T = void]

MSVC 中的全名:static constexpr std::string_view TypeName<T>::fullname_intern() [with T = void; std::string_view = std::basic_string_view<char>](但是这里是 'class s1::MyClass' 而不是 's1::MyClass')