为什么name()函数返回的字符串是实现定义的?

时间:2015-09-02 13:29:19

标签: c++ rtti typeid

请考虑以下示例:

#include <iostream>
#include <typeinfo>
int main()
{
    int a=9;
    std::cout << typeid(a).name() << '\n';
}

g ++ 4.8.1上的输出:i

MSVS 2010上的输出:int

为什么输出是编译器依赖?这背后的原因是什么?为什么它被保留为实现定义?为什么在所有编译器上没有相同的输出? C ++标准是否明确地说明了它?

5 个答案:

答案 0 :(得分:6)

因为编译器以不同的方式表示类型,并且不使用相同的内部结构。

G ++字符串是mangled类型名称,返回(而不是解码)工作更少,效率更高。要求编译器对这些字符串进行解码会增加更多工作量。该标准由实施者决定是否要这样做。

如果标准规定了它,那么它还必须指定各种事物,例如是说signed long还是仅long以及如何表示依赖于其他类型和常量的复杂模板实例化。标准化这些字符串的好处是非常小,但需要大量的工作。

答案 1 :(得分:2)

是的,C ++标准明确地说明了这一点:

18.7.1 $ 9,10 Class type_info [type.info]

const char* name() const noexcept; 
  

9返回:An   实施定义的ntbs   10备注:消息可能是a   以null结尾的多字节字符串(17.5.2.1.4.2),适用于   转换并显示为wstring(21.3,22.4.1.4)

答案 2 :(得分:1)

C ++标准说:

  

类type_info描述了由...生成的类型信息   实现。该类的对象有效地存储指向a的指针   类型的名称,以及适合比较两个的编码值   用于相等或整理顺序的类型。名称,编码规则和   类型的整理顺序都是未指定的,可能有所不同   程序之间。

g ++会返回你可以轻松解除的decorated name

另请参阅:Print variable type in C++

答案 3 :(得分:0)

为了扩展Jonathan Wakely的答案,typeid的典型用法是

if ( typeid(variable1) == typeid(variable2) )
     // same type

但也

if ( typeid(variable1).name() == typeid(variable2).name() )
    // same type

正如您所看到的,无需知道确切的实现定义名称。由于您并不真正需要,标准赋予实现自由,以更有效的方式实现它,这是相当不错的。

例如,比较 _ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ERKS6_S8_std::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) :绝对不那么冗长和有效,比较和存储。

答案 4 :(得分:0)

另外,typeid主要用于多态类型,以便在运行时检测多态对象类型:

#include <iostream>
#include <typeinfo>

class B
{
public:
    virtual ~B() {}
};

class D1 : public B
{

};

class D2 : public D1
{

};

int main()
{
    B* b1 = new D2;
    if (typeid(*b1) == typeid(B))
    {
        std::cout << "*b1 is B\n";
    }
    if (typeid(*b1) == typeid(D1))
    {
        std::cout << "*b1 is D1\n";
    }
    if (typeid(*b1) == typeid(D2))
    {
        std::cout << "*b1 is D2\n";
    }
}

这将打印

  

* b1是D2

因此它不适用于打印对象类型的名称。