2017-06-07 111 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