当前位置: 首页 > 知识库问答 >
问题:

我是否可以以一种配置方式获得C类型名称?

华恩
2023-03-14

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

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()只是常量字符*,而不是常量表达式。。。是否有其他的constexpr方法来获取类型的名称?

共有3个答案

骆英纵
2023-03-14

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

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

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

请注意:

Clang中的全名:静态std::string_viewTypeName

G中的全名:static constexpr std::string\u视图类型名

MSVC中的全名:class std::basic_string_view

柳杰
2023-03-14

编辑:根据对非constexpr特定问题的回答进行更新;这是几个人改进的结果,包括@HowardHinnant@康桓瑋 @瓦尔和我

据我所知,语言标准没有为获取类型名称提供任何便利。因此,我们求助于特定于编译器的方法。这适用于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);
}
瞿博学
2023-03-14

嗯,你可以,有点,但可能不太便于携带:

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

您可以将所需的类型\名称\长度定义为:

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

演示(适用于叮当声)

 类似资料:
  • 问题内容: 说我有两个JavaBeans 和。 如果创建一个Person对象的列表,我想编组成这样的东西: 可以使用这里描述的技术: 使用JAXB解组/编组List 通过使用和注释JaxbList,可以将其编组为上述XML。 但是,能够重用相同的类来封送对象列表也很好。实际上,我将有许多其他类型的bean。我可以这样: 但是,理想情况下,最好用类名的复数形式替换“列表”,用类名替换“ item”。

  • 问题内容: 假设我有一个.class文件,可以获取该类中包含的所有方法吗? 问题答案: 要了解所有方法,请在控制台中使用以下语句: 要么 或例如:

  • 我想要的是,每当数据被推入表中时,我的电子邮件(我已经配置了db_mail并正在工作)上会自动发出警报。 我在数据库和Windows server 2012 R2上拥有sa管理和完全权限

  • 问题内容: 假设我有一个数组数组 我想将其解析为对象。当我用 它似乎不起作用,我通过使用进行了工作 有一个更好的方法吗? 问题答案: 是的,请使用。 将允许你指定你真正想要的泛型类型,这有助于GSON找到类型来使用反序列化过程。 它使用这种宝石:。它是匿名类的事实使它成为的子类。相当于一个类 该方法的规范指出 如果超类是参数化类型,则返回的对象必须准确反映源代码中使用的实际类型参数。 如果指定 返

  • 那也许我可以 还是这是不可能的?也许只有在编译时了解了所有的信息,您才能做这种事情?

  • 这似乎表明含意没有被设定。我做错什么了吗?有办法把这个放在别处吗?