我想获取模板类型的字符串名称(const char*)。不幸的是我无法访问 RTTI。

template< typename T >
struct SomeClass
{
    const char* GetClassName() const { return /* magic goes here */; }
}

所以

SomeClass<int> sc;
sc.GetClassName();   // returns "int"

这可能吗?我找不到办法,准备放弃。谢谢您的帮助。

有帮助吗?

解决方案

没有,它不会与工作的typeid可靠无论是。它会给你依赖于编译器执行一些内部的字符串。像 “INT” 的东西,但也 “i” 是常见的int

顺便说一句,如果你想要的是只比较两个类型是否相同,你也不需要首先转换为字符串。你可以做

template<typename A, typename B>
struct is_same { enum { value = false }; };

template<typename A>
struct is_same<A, A> { enum { value = true }; };

和然后执行

if(is_same<T, U>::value) { ... }

升压已经有这样的模板,并且下一个C ++标准将有std::is_same太。

的类型手动注册

可以专门的类型是这样的:

template<typename> 
struct to_string {
    // optionally, add other information, like the size
    // of the string.
    static char const* value() { return "unknown"; }
};

#define DEF_TYPE(X) \
    template<> struct to_string<X> { \
        static char const* value() { return #X; } \
    }

DEF_TYPE(int); DEF_TYPE(bool); DEF_TYPE(char); ...

所以,你可以使用它像

char const *s = to_string<T>::value();

当然,你也可以摆脱主模板定义的(并且只保留了向前声明)如果你想如果类型是不知道得到一个编译时错误。我只是包括在这里完成。

我用字符常量的静态数据成员*前面,但他们会导致一些复杂的问题,这样的问题在那里把他们的声明,等等。班特像上面轻松地解决这个问题。

自动,取决于GCC

另一种方法是依靠编译器内部。在GCC,下面给出我合理的结果:

template<typename T>
std::string print_T() {
    return __PRETTY_FUNCTION__;
}

返回对std::string

  

std::string print_T() [with T = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]

substr混合一些find魔术会给你你查找字符串表示。

其他提示

真正简单的解决方法:只是传递一个字符串对象SomeClass的的构造,说是什么类型。

示例:

#define TO_STRING(type) #type
SomeClass<int> s(TO_STRING(int));

简单地存储并在GetClassName执行显示。

<强>稍微复杂的解决方案,但仍然很容易:

#define DEC_SOMECLASS(T, name) SomeClass<T> name;  name.sType = #T; 

template< typename T >
struct SomeClass
{
    const char* GetClassName() const { return sType.c_str(); }
    std::string sType;
};


int main(int argc, char **argv)
{
    DEC_SOMECLASS(int, s);
    const char *p = s.GetClassName();

    return 0;
}

<强>模板非类型的解决方案:

您也可以使自己的类型ID,并有一个功能转换和从ID和字符串表示。

然后,当声明的类型作为模板非类型参数可以传递ID:

template< typename T, int TYPEID>
struct SomeClass
{
    const char* GetClassName() const { return GetTypeIDString(TYPEID); }
};


...

SomeClass<std::string, STRING_ID> s1;
SomeClass<int, INT_ID> s2;

你可以尝试这样的事情(警告这只是我的想法,所以可能会出现编译错误等......)

template <typename T>
const char* GetTypeName()
{
    STATIC_ASSERT(0); // Not implemented for this type
}

#define STR(x) #x
#define GETTYPENAME(x) str(x) template <> const char* GetTypeName<x>() { return STR(x); }

// Add more as needed
GETTYPENAME(int)
GETTYPENAME(char)
GETTYPENAME(someclass)

template< typename T >
struct SomeClass
{
    const char* GetClassName() const { return GetTypeName<T>; }
}

这适用于您添加的任何类型 GETTYPENAME(type) 线为.它的优点是无需修改您感兴趣的类型即可工作,并且可以使用内置类型和指针类型。它确实有一个明显的缺点,即您必须为要使用的每种类型添加一行。

如果不使用内置 RTTI,您将必须自己在某处添加信息,无论是 Brian R.邦迪的回答或者德克特利的回答都会起作用。除了我的回答之外,您还可以在三个不同的位置添加该信息:

  1. 在对象创建时使用 SomeClass<int>("int")
  2. 在类中使用dirkgently的编译时RTTI或虚函数
  3. 使用我的解决方案的模板。

这三者都可以工作,问题只是在你的情况下,你最终会在哪里遇到最少的维护麻烦。

这是你没有访问RTTI,这是否意味着你不能使用的typeid(T)。名称()?因为这几乎是编译器的帮助下做到这一点的唯一方法。

这是非常重要的类型有唯一的名字,或者会以某种方式持续的名字?如果是这样,你应该考虑给他们的东西比在代码中声明的只是类的名称更稳健。你可以把它们放在不同的命名空间给两个类相同的不合格的名称。你也可以把两个类具有相同名称(包括名称空间限定)在Windows中两个不同的DLL文件,所以您需要将DLL识别的被包括在名称为好。

这一切都取决于你打算做琴弦,当然什么。

您可以自己添加一个小魔术。是这样的:

#include <iostream>

#define str(x) #x
#define xstr(x) str(x)
#define make_pre(C) concat(C, <)
#define make_post(t) concat(t, >)

#define make_type(C, T) make_pre(C) ## make_post(T)
#define CTTI_REFLECTION(T, x)  static std::string my_typeid() \
                               { return xstr(make_type(T, x)); }


// the dark magic of Compile Time Type Information (TM)
#define CTTI_REFLECTION(x)  static const char * my_typeid() \
                                  { return xstr(make_type(T, x)); }

#define CREATE_TEMPLATE(class_name, type) template<> \
                                    struct class_name <type>{ \
                                        CTTI_REFLECTION(class_name, type) \
                                    }; 

// dummy, we'll specialize from this later
template<typename T> struct test_reflection;

// create an actual class
CREATE_TEMPLATE(test_reflection, int)

struct test_reflection {
  CTTI_REFLECTION(test_reflection)
};

int main(int argc, char* argv[])
{
    std::cout << test_reflection<int>::my_typeid();
}

我会作出检查器static函数(因此非const)。

没有,对不起。

如果您尝试使用它INT RTTI甚至不会编译。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top