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

ein*_*ica 28 c++ reflection compile-time constexpr c++14

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

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

现在我希望:

template <typename T>
constexpr auto type_name_length = my_strlen(typeid(T).name());
Run Code Online (Sandbox Code Playgroud)

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

Jam*_*ree 70

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

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 {};
}
Run Code Online (Sandbox Code Playgroud)

您可以将您想要的定义type_name_length为:

template <typename T>
constexpr auto type_name_length = get_name<T>().size;
Run Code Online (Sandbox Code Playgroud)

DEMO(适用于clang&g ++)

  • 当然,仅适用于C++ 14或更高版本. (3认同)
  • 可以使用`__FUNCSIG__`在MSVC上实现类似的功能. (2认同)

ein*_*ica 15

编辑:根据对非 constexpr 特定问题的答案进行更新;它是包括 @HowardHinnant、@\xe5\xba\xb7\xe6\xa1\x93\xe7\x91\x8b @Val 和我自己在内的几个人改进的结果。

\n

据我所知,语言标准没有提供任何获取类型名称的设施。因此,我们采用特定于编译器的方法。这适用于 GCC、clang 和 MSVC。

\n
#include <string_view>\n// If you can\'t use C++17\'s standard library, you\'ll need to use the GSL \n// string_view or implement your own struct (which would not be very difficult,\n// since we only need a few methods here)\n\ntemplate <typename T> constexpr std::string_view type_name();\n\ntemplate <>\nconstexpr std::string_view type_name<void>()\n{ return "void"; }\n\nnamespace detail {\n\nusing type_name_prober = void;\n\ntemplate <typename T>\nconstexpr std::string_view wrapped_type_name() \n{\n#ifdef __clang__\n    return __PRETTY_FUNCTION__;\n#elif defined(__GNUC__)\n    return __PRETTY_FUNCTION__;\n#elif defined(_MSC_VER)\n    return __FUNCSIG__;\n#else\n#error "Unsupported compiler"\n#endif\n}\n\nconstexpr std::size_t wrapped_type_name_prefix_length() { \n    return wrapped_type_name<type_name_prober>().find(type_name<type_name_prober>()); \n}\n\nconstexpr std::size_t wrapped_type_name_suffix_length() { \n    return wrapped_type_name<type_name_prober>().length() \n        - wrapped_type_name_prefix_length() \n        - type_name<type_name_prober>().length();\n}\n\n} // namespace detail\n\ntemplate <typename T>\nconstexpr std::string_view type_name() {\n    constexpr auto wrapped_name = detail::wrapped_type_name<T>();\n    constexpr auto prefix_length = detail::wrapped_type_name_prefix_length();\n    constexpr auto suffix_length = detail::wrapped_type_name_suffix_length();\n    constexpr auto type_name_length = wrapped_name.length() - prefix_length - suffix_length;\n    return wrapped_name.substr(prefix_length, type_name_length);\n}\n
Run Code Online (Sandbox Code Playgroud)\n