获取派生模板实例化的运行时类型

时间:2017-06-07 12:53:15

标签: c++ templates rtti

我可以使用say typeiddynamic_cast在派生的基类实例之间切换。例如:

struct B { virtual ~B() {} };

struct D1 : B {};
struct D2 : B {};

void doit(B &b) {
  if      (dynamic_cast<D1 *>(&b)) foo1();
  else if (dynamic_cast<D2 *>(&b)) foo2();
}

当派生类型是模板实例时,如何继续这种情况?例如,我如何扩展上面的doit函数来处理四种情况;也许使用下面的DT1DT2类,用任意类型实例化?

template <typename T>
struct DT1 : B {};

template <typename T>
struct DT2 : B {};

1 个答案:

答案 0 :(得分:1)

您可以维护doit函数的某种注册表来调用每种类型,而不是对foo函数中的派生类列表进行硬编码。在最简单的形式中,这可能只是vector的{​​{1}},您只需循环并调用它们中的每一个。每个std::function<void(B&)>都负责检查类型是否匹配:

std::function

如果你想更聪明,注册表可能类似于auto& doitRegistry(){ static std::vector<std::function<void(B&)>> registry; return registry; } void doit(B &b) { for (auto& f : doitRegistry()) { f(b); } } ,这样你就不必遍历整个注册表,但只要你没有庞大的数字派生类可能并不重要。

然后,您只需在注册表中注册每种类型的派生类。您可以创建一个辅助类,在其构造函数中注册函数在注册表中:

std::unordered_map<std::type_index, std::function<void(B&)>>

为每个派生类创建此类的静态实例:

struct DoItRegistration {
  DoItRegistration(std::function<void(B&)> foo) {
     doitRegistry().push_back(std::move(foo));
  }
};

因此,在首次使用派生类时,它会将自己注册到template <typename T> struct DT1 : B { DT1() { registerWithDoIt(); } static DoItRegistration& registerWithDoIt() { static DoItRegistration registration([](B &b){ if (dynamic_cast<DT1<T>*>(&b)){ foo1(); } }); return registration; } }; 注册表,并在需要时调用:

doit

Live demo