C ++:type_info来区分类型

时间:2021-05-10 17:06:44

I know that compilers have much freedom in implementing std::type_info functions' behavior.

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

I'm thinking about using it to compare object types, so I'd like to be sure that:

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

  1. std::type_info::name must return two different strings for two different types.

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

  2. std::type_info::before must say that Type1 is before Type2 exclusive-or Type2 is before Type1.

    std :: type_info ::之前必须说Type1在Type2之前 - 或Type2在Type1之前。

    // like this:
    typeid(T1).before( typeid(T2) ) != typeid(T2).before( typeid(T1) )
    
  3. Two different specialization of the same template class are considered different types.

    相同模板类的两个不同的特化被认为是不同的类型。

  4. Two different typedef-initions of the same type are the same type.

    相同类型的两种不同类型的定义是相同的类型。

And finally:

  • Since std::type_info is not copyable, how could I store type_infos somewhere (eg: in a std::map)? The only way it to have a std::type_info always allocated somewhere (eg: on the stack or on a static/global variable) and use a pointer to it?

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

  • How fast are operator==, operator!= and before on most common compilers? I guess they should only compare a value. And how fast is typeid?

    operator ==,operator!=和大多数常见编译器之前的速度有多快?我猜他们应该只比较一个值。还有多快?

  • I've got a class A with a virtual bool operator==( const A& ) const. Since A has got many subclasses (some of which are unknown at compile time), I'd overload that virtual operator in any subclass B this way:

    我有一个带有虚拟bool运算符的类A =(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 ) );
    }
    

    Is this an acceptable (and standard) way to implement such operator?

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

5 个解决方案

#1


7  

After a quick look at the documentation, I would say that :

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

  1. std::type_info::name always returns two different strings for two different types, otherwise it means that the compiler lost itself while resolving types and you shouldn't use it anymore.

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

  2. Reference tells : "before returns true if the type precedes the type of rhs in the collation order. The collation order is just an internal order kept by a particular implementation and is not necessarily related to inheritance relations or declaring order." You therefore have the guarantee that no types has the same rank in the collation order.

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

  3. Each instantiation of a template class is a different type. Specialization make no exceptions.

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

  4. I don't really understand what you mean. If you mean something like having typedef foo bar; in two separate compilation units and that bar is the same in both, it works that way. If you mean typedef foo bar; typedef int bar;, it doesn't work (except if foo is int).

    我真的不明白你的意思。如果你的意思是像typedef foo bar;在两个单独的编译单元中,并且两者中的条形图相同,它以这种方式工作。如果你的意思是typedef foo bar; typedef int bar;,它不起作用(除非foo是int)。

About your other questions :

关于您的其他问题:

  • You should store references to std::type_info, of wrap it somehow.
  • 你应该存储对std :: type_info的引用,以某种方式包装它。

  • Absolutely no idea about performance, I assume that comparison operators have constant time despite of the type complexity. Before must have linear complexity depending on the number of different types used in your code.
  • 绝对不了解性能,我认为尽管类型复杂,比较运算符仍然具有恒定的时间。之前必须具有线性复杂性,具体取决于代码中使用的不同类型的数量。

  • This is really strange imho. You should overload your operator== instead of make it virtual and override it.
  • 这真是奇怪的imho。您应该重载您的运算符==而不是使其成为虚拟并覆盖它。

#2


4  

Standard 18.5.1 (Class type_info) :

标准18.5.1(Class type_info):

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.

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

From my understanding :

根据我的理解:

  1. You don't have this guarantee regarding std:type_info::name. The standard only states that name returns an implementation-defined NTBS, and I believe a conforming implementation could very well return the same string for every type.
  2. 您没有关于std:type_info :: name的此保证。标准只声明name返回一个实现定义的NTBS,我相信一致的实现很可能为每个类型返回相同的字符串。

  3. I don't know, and the standard isn't clear on this point, so I wouldn't rely on such behavior.
  4. 我不知道,标准在这一点上并不清楚,所以我不会依赖这种行为。

  5. That one should be a definite 'Yes' for me
  6. 那对我来说应该是一个明确的“是”

  7. That one should be a definite 'Yes' for me
  8. 那对我来说应该是一个明确的“是”

Regarding the second set of questions :

关于第二组问题:

  • No, you cannot store a type_info. Andrei Alexandrescu proposes a TypeInfo wrapper in its Modern C++ Design book. Note that the objects returned by typeid have static storage so you can safely store pointers without worrying about object lifetime
  • 不,您不能存储type_info。 Andrei Alexandrescu在其Modern C ++ Design书中提出了一个TypeInfo包装器。请注意,typeid返回的对象具有静态存储,因此您可以安全地存储指针,而无需担心对象的生命周期

  • I believe you can assume that type_info comparison are extremely efficient (there really isn't much to compare).
  • 我相信你可以假设type_info比较非常有效(实际上没有太多的比较)。

#3


3  

You can store it like this.

你可以像这样存储它。

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

EDIT:

C++ standard 5.2.8.

C ++标准5.2.8。

The result of a typeid expression is an lvalue of static type const std::type_info...

typeid表达式的结果是静态类型const std :: type_info的左值...

Which means you can use it like this.

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

my_type_info(typeid(my_type));

The typeid function returns an lvalue (it is not temporary) and therefore the address of the returned type_info is always valid.

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

#4


1  

The current answers for questions 1 and 2 are perfectly correct, and they're essentially just details for the type_info class - no point in repeating those answers.

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

For questions 3 and 4, it's important to understand what precisely is a type in C++, and how they relate to names. For starters, there are a whole bunch of predefined types, and those have names: int, float, double. Next, there are some constructed types that do not have names of their own: const int, int*, const int*, int* const. There are function types int (int) and function pointer types int (*)(int).

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

It's sometimes useful to give a name to an unnamed type, which is possible using typedef. For instance, typedef int* pint or typedef int (*pf)(int);. This introduces a name, not a new type.

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

Next are user-defined types: structs, classes, unions. There's a good convention to give them names, but it's not mandatory. Don't add such a name with typedef, you can do so directly: struct Foo { }; instead of typedef struct {} Foo;. It's common to have class definitions in headers, which end up\ in multiple translation units. That does mean the class is defined more than once. This is still the same type, and therefore you aren't allowed to play tricks with macros to change the class member definitions.

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

A template class is not a type, it's a recipe for types. Two instantiations of a single class template are distinct types if the template arguments are different types (or values). This works recursively: Given template <typename T> struct Foo{};, Foo<Foo<int> > is the same type as Foo<Foo<Bar> > if and only if Bar is another name for the type int.

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

#5


0  

Type_info is implementation defined so I really wouldn't rely on it. However, based on my experiences using g++ and MSVC, assumptions 1,3 and 4 hold... not really sure about #2.

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

Is there any reason you can't use another method like this?

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

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

#1


7  

After a quick look at the documentation, I would say that :

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

  1. std::type_info::name always returns two different strings for two different types, otherwise it means that the compiler lost itself while resolving types and you shouldn't use it anymore.

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

  2. Reference tells : "before returns true if the type precedes the type of rhs in the collation order. The collation order is just an internal order kept by a particular implementation and is not necessarily related to inheritance relations or declaring order." You therefore have the guarantee that no types has the same rank in the collation order.

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

  3. Each instantiation of a template class is a different type. Specialization make no exceptions.

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

  4. I don't really understand what you mean. If you mean something like having typedef foo bar; in two separate compilation units and that bar is the same in both, it works that way. If you mean typedef foo bar; typedef int bar;, it doesn't work (except if foo is int).

    我真的不明白你的意思。如果你的意思是像typedef foo bar;在两个单独的编译单元中,并且两者中的条形图相同,它以这种方式工作。如果你的意思是typedef foo bar; typedef int bar;,它不起作用(除非foo是int)。

About your other questions :

关于您的其他问题:

  • You should store references to std::type_info, of wrap it somehow.
  • 你应该存储对std :: type_info的引用,以某种方式包装它。

  • Absolutely no idea about performance, I assume that comparison operators have constant time despite of the type complexity. Before must have linear complexity depending on the number of different types used in your code.
  • 绝对不了解性能,我认为尽管类型复杂,比较运算符仍然具有恒定的时间。之前必须具有线性复杂性,具体取决于代码中使用的不同类型的数量。

  • This is really strange imho. You should overload your operator== instead of make it virtual and override it.
  • 这真是奇怪的imho。您应该重载您的运算符==而不是使其成为虚拟并覆盖它。

#2


4  

Standard 18.5.1 (Class type_info) :

标准18.5.1(Class type_info):

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.

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

From my understanding :

根据我的理解:

  1. You don't have this guarantee regarding std:type_info::name. The standard only states that name returns an implementation-defined NTBS, and I believe a conforming implementation could very well return the same string for every type.
  2. 您没有关于std:type_info :: name的此保证。标准只声明name返回一个实现定义的NTBS,我相信一致的实现很可能为每个类型返回相同的字符串。

  3. I don't know, and the standard isn't clear on this point, so I wouldn't rely on such behavior.
  4. 我不知道,标准在这一点上并不清楚,所以我不会依赖这种行为。

  5. That one should be a definite 'Yes' for me
  6. 那对我来说应该是一个明确的“是”

  7. That one should be a definite 'Yes' for me
  8. 那对我来说应该是一个明确的“是”

Regarding the second set of questions :

关于第二组问题:

  • No, you cannot store a type_info. Andrei Alexandrescu proposes a TypeInfo wrapper in its Modern C++ Design book. Note that the objects returned by typeid have static storage so you can safely store pointers without worrying about object lifetime
  • 不,您不能存储type_info。 Andrei Alexandrescu在其Modern C ++ Design书中提出了一个TypeInfo包装器。请注意,typeid返回的对象具有静态存储,因此您可以安全地存储指针,而无需担心对象的生命周期

  • I believe you can assume that type_info comparison are extremely efficient (there really isn't much to compare).
  • 我相信你可以假设type_info比较非常有效(实际上没有太多的比较)。

#3


3  

You can store it like this.

你可以像这样存储它。

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

EDIT:

C++ standard 5.2.8.

C ++标准5.2.8。

The result of a typeid expression is an lvalue of static type const std::type_info...

typeid表达式的结果是静态类型const std :: type_info的左值...

Which means you can use it like this.

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

my_type_info(typeid(my_type));

The typeid function returns an lvalue (it is not temporary) and therefore the address of the returned type_info is always valid.

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

#4


1  

The current answers for questions 1 and 2 are perfectly correct, and they're essentially just details for the type_info class - no point in repeating those answers.

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

For questions 3 and 4, it's important to understand what precisely is a type in C++, and how they relate to names. For starters, there are a whole bunch of predefined types, and those have names: int, float, double. Next, there are some constructed types that do not have names of their own: const int, int*, const int*, int* const. There are function types int (int) and function pointer types int (*)(int).

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

It's sometimes useful to give a name to an unnamed type, which is possible using typedef. For instance, typedef int* pint or typedef int (*pf)(int);. This introduces a name, not a new type.

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

Next are user-defined types: structs, classes, unions. There's a good convention to give them names, but it's not mandatory. Don't add such a name with typedef, you can do so directly: struct Foo { }; instead of typedef struct {} Foo;. It's common to have class definitions in headers, which end up\ in multiple translation units. That does mean the class is defined more than once. This is still the same type, and therefore you aren't allowed to play tricks with macros to change the class member definitions.

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

A template class is not a type, it's a recipe for types. Two instantiations of a single class template are distinct types if the template arguments are different types (or values). This works recursively: Given template <typename T> struct Foo{};, Foo<Foo<int> > is the same type as Foo<Foo<Bar> > if and only if Bar is another name for the type int.

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

#5


0  

Type_info is implementation defined so I really wouldn't rely on it. However, based on my experiences using g++ and MSVC, assumptions 1,3 and 4 hold... not really sure about #2.

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

Is there any reason you can't use another method like this?

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

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