我可以使用say typeid
或dynamic_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
函数来处理四种情况;也许使用下面的DT1
和DT2
类,用任意类型实例化?
template <typename T>
struct DT1 : B {};
template <typename T>
struct DT2 : B {};
答案 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