使用std :: type_index

时间:2016-04-18 19:31:04

标签: c++11 inheritance types

我一直在寻找Visitor模式的替代方案,以映射类层次结构中类型的行为,并允许多次调度。每次向类层次结构添加新类型时,都必须更新所有支持访问者。所以我遇到std::type_index,根据cppreference.com可能会做到这一点。然后我想,现在我必须为每个子类实现get_type_index,这与访问者模式的accept方法有关。这只是工作的一半 必须为Visitor模式完成。但后来我发现,显然你只需要在基类中实现一个(非纯)虚函数来使整个事情发挥作用。以下是我的code,我有以下问题:

  • 为什么类型正确地映射到继承自BaseVirtual
  • 的类
  • 编译器如何做到这一点以及它有多贵?
  • 可移动吗?
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <typeindex>

struct Base
{
  std::type_index get_type_index( ) const
  {
    return std::type_index( typeid(*this) );
  }
};

struct BaseVirtual
{
  virtual std::type_index get_type_index( ) const
  {
    return std::type_index( typeid(*this) );
  }
};

template<typename BaseType>
struct A : public BaseType
{
};

template<typename BaseType>
struct B : public BaseType
{
};

template<typename BaseType>
struct C : public BaseType
{
};

int main( int argc,
          char **argv )
{
  std::map<std::type_index, std::string> typeToStringMap = { { std::type_index( typeid(Base) ), "Base" }, { std::type_index( typeid(A<Base> ) ), "ABase" }, { std::type_index( typeid(B<Base> ) ), "BBase" }, { std::type_index( typeid(C<Base> ) ), "CBase" }, { std::type_index( typeid(BaseVirtual) ),
      "BaseVirtual" }, { std::type_index( typeid(A<BaseVirtual> ) ), "ABaseVirtual" }, { std::type_index( typeid(B<BaseVirtual> ) ), "BBaseVirtual" }, { std::type_index( typeid(C<BaseVirtual> ) ), "CBaseVirtual" } };

  A<Base> a;
  B<Base> b;
  C<Base> c;

  A<BaseVirtual> av;
  B<BaseVirtual> bv;
  C<BaseVirtual> cv;

  auto asp = std::make_shared<A<Base>>( );
  auto bsp = std::make_shared<B<Base>>( );
  auto csp = std::make_shared<C<Base>>( );

  auto avsp = std::make_shared<A<BaseVirtual>>( );
  auto bvsp = std::make_shared<B<BaseVirtual>>( );
  auto cvsp = std::make_shared<C<BaseVirtual>>( );

  A<Base>* ap = new A<Base>;
  B<Base>* bp = new B<Base>;
  C<Base>* cp = new C<Base>;

  A<BaseVirtual>* avp = new A<BaseVirtual>;
  B<BaseVirtual>* bvp = new B<BaseVirtual>;
  C<BaseVirtual>* cvp = new C<BaseVirtual>;

  std::cout << typeToStringMap[a.get_type_index( )] << std::endl;
  std::cout << typeToStringMap[b.get_type_index( )] << std::endl;
  std::cout << typeToStringMap[c.get_type_index( )] << std::endl;
  std::cout << typeToStringMap[av.get_type_index( )] << std::endl;
  std::cout << typeToStringMap[bv.get_type_index( )] << std::endl;
  std::cout << typeToStringMap[cv.get_type_index( )] << std::endl;

  std::cout << typeToStringMap[asp->get_type_index( )] << std::endl;
  std::cout << typeToStringMap[bsp->get_type_index( )] << std::endl;
  std::cout << typeToStringMap[csp->get_type_index( )] << std::endl;
  std::cout << typeToStringMap[avsp->get_type_index( )] << std::endl;
  std::cout << typeToStringMap[bvsp->get_type_index( )] << std::endl;
  std::cout << typeToStringMap[cvsp->get_type_index( )] << std::endl;

  std::cout << typeToStringMap[ap->get_type_index( )] << std::endl;
  std::cout << typeToStringMap[bp->get_type_index( )] << std::endl;
  std::cout << typeToStringMap[cp->get_type_index( )] << std::endl;
  std::cout << typeToStringMap[avp->get_type_index( )] << std::endl;
  std::cout << typeToStringMap[bvp->get_type_index( )] << std::endl;
  std::cout << typeToStringMap[cvp->get_type_index( )] << std::endl;
}

输出:

Base
Base
Base
ABaseVirtual
BBaseVirtual
CBaseVirtual
Base
Base
Base
ABaseVirtual
BBaseVirtual
CBaseVirtual
Base
Base
Base
ABaseVirtual
BBaseVirtual
CBaseVirtual

1 个答案:

答案 0 :(得分:1)

  

为什么类型正确地映射到继承自BaseVirtual

的类

因为C ++标准说他们应该:

  

[expr.typeid] / 2 typeid应用于类型为多态类类型(10.3)的glvalue表达式时,结果引用std::type_info表示glvalue引用的最派生对象(1.8)(即动态类型)类型的对象。

  

编译器是如何做到的,它有多贵?

无关的实施细节。一种方法是向vtable添加指向type_info或类似事物的指针。

  

可携带吗?

是的。同样,您观察到的行为是C ++标准规定的。