C ++:type_info来区分类型

时间:2010-11-16 12:39:20

标签: c++ typeid typeinfo

我知道编译器可以很自由地实现std::type_info函数的行为。

我正在考虑使用它来比较对象类型,所以我想确定:

  1. std::type_info::name必须为两种不同的类型返回两个不同的字符串。

  2. std::type_info::before必须说Type1 之前 Type2 exclusive-or Type2 < em>之前 Type1

    // like this:
    typeid(T1).before( typeid(T2) ) != typeid(T2).before( typeid(T1) )
    
  3. 同一模板类的两种不同特化被认为是不同的类型。

  4. 两种不同的typedef - 相同类型的相同类型。

  5. 最后:

    • 由于std::type_info不可复制,我如何将type_info存储在某处(例如:在std::map中)?只有std::type_info始终在某处分配(例如:在堆栈上或在静态/全局变量上)并使用指向它的指针的唯一方法是什么?

    • operator==operator!=before在大多数常见编译器上的速度有多快?我猜他们应该只比较一个值。 typeid的速度有多快?

    • 我有一个A的课程virtual bool operator==( const A& ) const。由于A有许多子类(其中一些在编译时是未知的),我会以这种方式在任何子类B中重载该虚拟运算符:

      virtual bool operator==( const A &other ) const {
        if( typeid(*this) != typeid(other) ) return false;
        // bool B::operator==( const B &other ) const // is defined for any class B
        return operator==( static_cast<B&>( other ) );
      }
      

      这是实现此类运营商的可接受(和标准)方式吗?

5 个答案:

答案 0 :(得分:8)

快速浏览一下文档后,我会说:

  1. std :: type_info :: name总是为两种不同的类型返回两个不同的字符串,否则就意味着编译器在解析类型时会自行丢失,你不应再使用它了。

  2. 引用告诉:“如果类型在整理顺序中的rhs类型之前,则返回true。归类顺序只是由特定实现保留的内部顺序,并不一定与继承关系或声明顺序相关“。 因此,您可以保证在整理顺序中没有类型具有相同的排名。

  3. 模板类的每个实例化都是不同的类型。专业化不例外。

  4. 我真的不明白你的意思。如果您的意思是在两个单独的编译单元中使用typedef foo bar;并且两者中的条形图相同,那么它就是这样的。如果你的意思是typedef foo bar; typedef int bar;,它就不起作用(除非foo是int)。

  5. 关于您的其他问题:

    • 你应该存储对std :: type_info的引用,以某种方式包装它。
    • 绝对不了解性能,我认为即使类型复杂,比较运算符也有恒定的时间。之前必须具有线性复杂性,具体取决于代码中使用的不同类型的数量。
    • 这真是奇怪的imho。您应该重载operator==而不是将其设为虚拟并覆盖它。

答案 1 :(得分:4)

标准18.5.1(Class type_info):

  

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

根据我的理解:

  1. 您对std:type_info::name没有此保证。该标准仅声明name返回实现定义的NTBS ,并且我相信符合标准的实现可以为每种类型返回相同的字符串。
  2. 我不知道,标准在这一点上并不清楚,所以我不会依赖这种行为。
  3. 那个人对我来说应该是肯定的'是'
  4. 那个人对我来说应该是肯定的'是'
  5. 关于第二组问题:

    • 不,您无法存储type_info。 Andrei Alexandrescu在其Modern C++ Design书中提出了TypeInfo封面。请注意, typeid返回的对象具有静态存储,因此您可以安全地存储指针而无需担心对象生存期
    • 我相信你可以认为type_info比较非常有效(实际上没有太多可比性)。

答案 2 :(得分:3)

您可以像这样存储它。

class my_type_info
{
public:
     my_type_info(const std::type_info& info) : info_(&info){}
     std::type_info get() const { return *info_;}
private:
     const std::type_info* info_;
};

编辑:

C ++标准5.2.8。

  

结果   typeid表达式是一个左值   static类型const std :: type_info ...

这意味着您可以像这样使用它。

my_type_info(typeid(my_type));

typeid函数返回一个左值(它不是临时的),因此返回的type_info的地址始终有效。

答案 3 :(得分:1)

问题1和2的当前答案是完全正确的,它们基本上只是type_info类的详细信息 - 没有必要重复这些答案。

对于问题3和4,了解C ++中的类型究竟是什么以及它们与名称的关系非常重要。对于初学者,有一大堆预定义类型,其名称为int, float, double。接下来,有些构造类型 not 具有自己的名称:const int, int*, const int*, int* const。有函数类型int (int)和函数指针类型int (*)(int)

为未命名的类型命名有时很有用,可以使用typedef。例如,typedef int* pinttypedef int (*pf)(int);。这引入了一个名称,而不是一个新类型。

接下来是用户定义的类型:结构,类,联合。为他们命名是一个很好的惯例,但这不是强制性的。不要使用typedef添加这样的名称,您可以直接执行此操作:struct Foo { };而不是typedef struct {} Foo;。在标题中有类定义是很常见的,最终在多个翻译单元中。这确实意味着该类被定义不止一次。这仍然是相同的类型,因此不允许您使用宏来改变类成员定义。

模板类不是类型,它是类型的配方。如果模板参数是不同的类型(或值),则单个类模板的两个实例是不同的类型。这是递归的:给定template <typename T> struct Foo{};Foo<Foo<int> >Foo<Foo<Bar> >的类型相同,当且仅当Bar是类型int的另一个名称。

答案 4 :(得分:0)

Type_info是实现定义的,所以我真的不会依赖它。但是,根据我使用g ++和MSVC的经验,假设1,3和4保持......不太确定#2。

你有什么理由不能使用这样的其他方法吗?

template<typename T, typename U>
struct is_same       { static bool const result = false; };

template<typename T>
struct is_same<T, T> { static bool const result = true;  };

template<typename S, typename T>
bool IsSame(const S& s, const T& t) {   return is_same<S,T>::result; }