为什么 name() 函数返回的字符串是实现定义的?
Why strings returned by name() function is implementation defined?
考虑以下示例:
#include <iostream>
#include <typeinfo>
int main()
{
int a=9;
std::cout << typeid(a).name() << '\n';
}
g++ 4.8.1 上的输出:i
MSVS 2010 的输出:整数
为什么输出依赖于编译器?这背后的原因是什么?为什么它保留为实现定义?为什么所有编译器的输出不同? C++ 标准是否明确说明?
C++ 标准说:
The class type_info describes type information generated by the
implementation. Objects of this class effectively store a pointer to a
name for the type, and an encoded value suitable for comparing two
types for equality or collating order. The names, encoding rule, and
collating sequence for types are all unspecified and may differ
between programs.
g++ 返回给您 decorated name,您可以轻松地对其进行分解。
另请参阅:Print variable type in C++
因为编译器以不同的方式表示类型并且不使用相同的内部结构。
G++ 字符串是 mangled 类型名称,返回它(而不是对其进行分解)工作更少,效率更高。要求编译器分解这些字符串会增加更多工作。该标准让实施者决定是否要这样做。
如果标准规定了它,那么它还必须指定各种事情,比如是说 signed long
还是只说 long
以及如何表示依赖于其他类型的复杂模板实例化和常量。标准化这些字符串的好处很小,但工作量很大。
是的,C++ 标准明确指出:
18.7.1$9,10 Class type_info [type.info]
const char* name() const noexcept;
9 Returns: An
implementation-defined ntbs.
10 Remarks: The message may be a
null-terminated multibyte string (17.5.2.1.4.2), suitable for
conversion and display as a wstring (21.3, 22.4.1.4)
为了扩展 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&)
:比较和存储绝对不那么冗长和高效。
另外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 is D2
因此它不适用于打印对象类型的名称。
考虑以下示例:
#include <iostream>
#include <typeinfo>
int main()
{
int a=9;
std::cout << typeid(a).name() << '\n';
}
g++ 4.8.1 上的输出:i
MSVS 2010 的输出:整数
为什么输出依赖于编译器?这背后的原因是什么?为什么它保留为实现定义?为什么所有编译器的输出不同? C++ 标准是否明确说明?
C++ 标准说:
The class type_info describes type information generated by the implementation. Objects of this class effectively store a pointer to a name for the type, and an encoded value suitable for comparing two types for equality or collating order. The names, encoding rule, and collating sequence for types are all unspecified and may differ between programs.
g++ 返回给您 decorated name,您可以轻松地对其进行分解。
另请参阅:Print variable type in C++
因为编译器以不同的方式表示类型并且不使用相同的内部结构。
G++ 字符串是 mangled 类型名称,返回它(而不是对其进行分解)工作更少,效率更高。要求编译器分解这些字符串会增加更多工作。该标准让实施者决定是否要这样做。
如果标准规定了它,那么它还必须指定各种事情,比如是说 signed long
还是只说 long
以及如何表示依赖于其他类型的复杂模板实例化和常量。标准化这些字符串的好处很小,但工作量很大。
是的,C++ 标准明确指出:
18.7.1$9,10 Class type_info [type.info]
const char* name() const noexcept;
9 Returns: An implementation-defined ntbs.
10 Remarks: The message may be a null-terminated multibyte string (17.5.2.1.4.2), suitable for conversion and display as a wstring (21.3, 22.4.1.4)
为了扩展 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&)
:比较和存储绝对不那么冗长和高效。
另外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 is D2
因此它不适用于打印对象类型的名称。