2012-02-19 81 views
3

我正在寫一些代碼,我有一個類可以接受mixin作爲可變參數的模板。但是,我還需要mixin能夠通過CRTP慣用語訪問基類。這裏有一個小例子,是不能完全做到我想要的東西:廣義Mixins

template <template <class> class... Mixins> 
class Foo : Mixins<Foo<Mixins...>>... {}; 

不過,我可能會傳遞給Foo一個mixin會,在一般情況下,有幾個模板參數,就像這樣:

template <class Derived, class Type1, class Type2> 
class Bar 
{ 
    Derived& operator()() 
    { 
     return static_cast<Derived&>(*this); 
    } 
}; 

如何我可以更改Foo,以便我可以從多個基類繼承它,我控制每個基類接受的模板參數?如果我遞模板模板參數的列表以及傳遞給它們的參數列表,那麼我就不會看到如何將每個模板參數與它的參數關聯起來。到目前爲止,我想到了這樣的事情,但我不知道我會如何繼續。

template <template <class...> class T, 
    template <class...> class... Ts> 
class Foo : /* How do I retrieve the arguments? */ 

回答

4

我不太清楚我是否理解了這個問題,所以請讓我重新修改它,以便我們可以從右腳開始。

您需要在一個典型的CRTP用例中將派生類型線程化到基類,同時將其他模板參數傳遞給各個基類。

也就是說,一個典型的基類將是:

template <typename Derived, typename X, typename Y> 
struct SomeBase { 
}; 

而你要需要創建您的類型,這樣就可以控制XY,並在同一時間通過完整Derived類。


我想我會用apply招生成的基類上的蒼蠅,從Derived類的參數列表提供的適配器。

typedef MyFoo< SomeBaseFactory<int, float> > SuperFoo; 

Foo被定義爲:

template <typename... Args> 
struct Foo: apply<Args, Foo<Args...>>::type... { 
}; 

而只是因爲,因爲我在模板中拖着沉重的腳步如此之深它已經有一段時間

template <typename Derived, typename X, typename Y> 
struct SomeBase {}; 

template <typename X, typename Y> 
struct SomeBaseFactory { 
    template <typename Derived> 
    struct apply { typedef SomeBase<Derived, X, Y> type; }; 
}; 

// Generic application 
template <typename Fac, typename Derived> 
struct apply { 
    typedef typename Fac::template apply<Derived>::type type; 
}; 

然後,您將創建類型,I checked it worked


當然,Factory本身是不是一個真正的針對特定的類型,所以我們可以重用你嘗試過包裝方法:

template <template <typename...> class M, typename... Args> 
struct Factory { 
    template <typename Derived> 
    struct apply { typedef M<Derived, Args...> type; }; 
}; 

是的,it works too

+0

這顯然是最優雅的解決方案;對不起,如果我的問題有點含糊不清。 – 2012-02-19 19:56:06

+0

@ void-pointer:我不一定會說模棱兩可,有幾層需要挖掘,所以我想最好清楚地表達我正在試圖解決的問題,這樣如果我朝錯誤的方向前進,就可以糾正我的問題:) – 2012-02-19 20:09:01

2

如果我正確理解你的問題,你應該創建模板別名,以減少每個mixin到一個模板參數。

template <typename Derived> 
using BarIntFloat = Bar<Derived, Int, Float>; 

template <typename Derived> 
using BazQux = Baz<Derived, Qux>; 

typedef Foo<BarIntFloat, BazQux> MyFoo; 
+0

我沒有想過使用模板別名來實現這一點 - 謝謝你的答案。需要注意的是,由於需要使用更多mixin,所以事情變得不方便。我想出了一個似乎沒有模板別名的黑客,但也許有更好的方法來做到這一點? – 2012-02-19 09:39:04

+0

我認爲你需要一個模板別名來獲得CRTP,但是你可以把它包裝到你的包裝中以獲得一些很好用的東西。對不起,我目前沒有支持別名的編譯器,所以我無法測試。 – 2012-02-19 10:17:12

+0

嗯,我的解決方案似乎按預期工作,沒有模板別名,但我沒有支持模板別名的編譯器。 g ++ 4.7可以,但是我想等到官方發佈。 – 2012-02-19 19:52:17

0

這是我提出的解決方案。可能有一個更優雅的方式來做到這一點,但我想不出任何。一個需要注意的是,所有使用的mixin都需要首先嵌套在wrapper結構中,以及它們各自的參數。

template <template <class...> class Mixin, class... Args> 
struct wrapper 
{ 
     typedef Mixin<Args...> type; 
}; 

template <class... Args> 
struct test 
{ 

}; 

template <class Arg, class... Args> 
struct test<Arg, Args...> : Arg::type, test<Args...> 
{ 

}; 

template <class T> 
class mixin1 {}; 

template <class T1, class T2> 
class mixin2 {}; 

template <class T1, class T2, class T3> 
class mixin3 {}; 

int main() 
{ 
     test<wrapper<mixin1, int>, wrapper<mixin2, int, float>> foo; 
     return 0; 
} 
0

@空指針

這是可變參數模板基本遺漏。用戶不能在T由安德烈Alexandrescu的融入本土2012演講獲得第i個類型...或者從值的第i個值...

這裏是a link

template <typename... Ts> 
void fun(const Ts&... vs) {} 

•Ts不一種; vs不是一個價值!

typedef Ts MyList; // error! 
Ts var; // error! 
auto copy = vs; // error! 

所以Ts/vs應該是某種元組。

+0

我想你有些錯過了這個問題,我沒有看到任何提示索引訪問預期的提示。 – 2012-02-19 11:02:32

+0

「用戶無法從T獲取第i個類型」 - 容易,只需將'T ...'解壓縮到'std :: tuple'中並使用'std :: tuple_element'即可。相同的值'... ...。 – Xeo 2012-02-19 22:51:47