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

新手上路,请多包涵

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

 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 ……还有其他一些 constexpr 方法来获取类型的名称吗?

原文由 einpoklum 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 634
2 个回答

编辑: 根据对非 constexpr 特定问题的 答案 进行更新;这是包括@HowardHinnant、@康桓玮、@Val 和我自己在内的几个人改进的结果。

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

 #include <string_view>
// If you can't use C++17's standard library, you'll need to use the GSL
// string_view or implement your own struct (which would not be very difficult,
// since we only need a few methods here)

template <typename T> constexpr std::string_view type_name();

template <>
constexpr std::string_view type_name<void>()
{ return "void"; }

namespace detail {

using type_name_prober = void;

template <typename T>
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<type_name_prober>().find(type_name<type_name_prober>());
}

constexpr std::size_t wrapped_type_name_suffix_length() {
    return wrapped_type_name<type_name_prober>().length()
        - wrapped_type_name_prefix_length()
        - type_name<type_name_prober>().length();
}

} // namespace detail

template <typename T>
constexpr std::string_view type_name() {
    constexpr auto wrapped_name = detail::wrapped_type_name<T>();
    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);
}

原文由 einpoklum 发布,翻译遵循 CC BY-SA 4.0 许可协议

好吧,你可以,有点,但可能不太便携:

 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;

演示(适用于 clang 和 g++)

原文由 Jamboree 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题