2017-06-07 83 views
2

我可以使用说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

*“我该如何继续下去”* - 通过使'doit'成为函数模板。你真正要求的是范式的混合体(编译模板类型与运行时动态类型)。这不会很好。 – IInspectable

+2

这可能会有助于描述你的总体目标,因为有人可能有不同的方式来处理这个问题,这会更好地工作。另外,您可以考虑查看[Boost.Variant](http://www.boost.org/doc/libs/1_64_0/doc/html/variant.html)。 – SirGuy

回答

1

而是在doit功能硬编码派生类的列表,你可以保持某种foo功能注册表的呼吁每种类型。最简单的形式可能是vectorstd::function<void(B&)>,你只需循环并调用它们中的每一个。

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&)>>,这样你就不必遍历整个注册表,但只要:如果类型匹配每个std::function将负责检查你没有大量的派生类,它可能并不重要。

然后你只需要在注册表中注册每种类型的派生类。您可以创建在其构造函数登记处登记功能的辅助类:

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注册表并在需要时将被称作:

int main() { 
    DT1<double> d1; 
    DT1<int> d2; 
    DT2<double> d3; 
    DT1<double> dupeType; 

    doit(d3); // calls foo2() 
} 

Live demo

+0

现在,这是在盒子外面思考。谢谢。我真的很希望有一个只修改'doit'功能的解决方案。这可能是不可能的。 – user2023370