2012-02-01 64 views
1

我知道我可以擴大一個元組的參數包到基類 的像這樣的可變參數模板:可以創建一個沒有元組的複合構造函數嗎?

#include <tuple> 
struct ComponentA { 
    int foo; 
    int bar; 
    ComponentA(std::tuple<int, int> && pack): 
     foo(std::get<0>(pack)), 
     bar(std::get<1>(pack)) 
    {} 
}; 

struct ComponentB { 
    ComponentB(std::tuple<> && pack) 
    {} 
}; 

template<typename ... Bases> 
struct CompositeClass: public Bases... { 
    template<typename ... Arguments> 
    CompositeClass(Arguments &&... arguments): 
     Bases(std::forward<Arguments>(arguments))... 

    {} 
}; 

int main() { 
    CompositeClass<ComponentA, ComponentB> composite{ 
     std::make_tuple(100, 100), 
     std::make_tuple() 
    }; 
} 

然而,我發現語法繁瑣。有沒有一種方法可以完全避免元組?

編輯:

更多的東西是這樣的:

struct ComponentA { 
    int foo; 
    int bar; 
    ComponentA(int a, int b): 
     foo(a), 
     bar(b) 
    {} 
}; 

struct ComponentB { 
    ComponentB() 
    {} 
}; 

template<typename ... Bases> 
struct CompositeClass: public Bases... { 
    template<typename ... ... Arguments> 
    CompositeClass(Arguments &&... ... arguments): 
     Bases(std::forward<Arguments>(arguments)...)... 
    {} 
}; 

int main() { 
    CompositeClass<ComponentA, ComponentB> composite{100, 100}; 
} 

兩個參數傳遞給ComponentA,無人以componentB。

編輯2

所以我有這樣的事情:

template <int ...> 
struct SequenceContainer {}; 

template <int, typename> 
struct AppendIntToSequence; 

template <int Value, int ... Sequence> 
struct AppendIntToSequence<Value, SequenceContainer<Sequence...>> { 
    typedef SequenceContainer<Sequence..., Value> type; 
}; 

template<int End> 
struct MakeSequence: 
    AppendIntToSequence<End - 1, typename MakeSequence<End - 1>::type> {}; 

template<> 
struct MakeSequence<0> { 
    typedef SequenceContainer<> type; 
}; 

struct ComponentA { 
    static const int parameters = 2; 
    ComponentA(int && a, int && b) { 
     std::cout << a << b << std::endl; 
    } 
}; 

struct ComponentB { 
    static const int parameters = 1; 
    ComponentB(const char * string) { 
     std::cout << string << std::endl; 
    } 
}; 

template <typename Base> 
struct TupleConstructor: Base { 
    template <typename ... Arguments, int ... Sequence> 
    TupleConstructor(std::tuple<Arguments...> &&, SequenceContainer<Sequence...> const &); 
}; 

template <typename Base> 
template <typename ... Arguments, int... Sequence> 
TupleConstructor<Base>::TupleConstructor(std::tuple<Arguments...> && arguments, SequenceContainer<Sequence...> const &): 
    Base(std::forward<Arguments>(std::get<Sequence>(arguments))...) 
{} 


template <typename ... Components> 
struct CompositeClass: public TupleConstructor<Components>... { 
    template <typename ... Arguments> 
    CompositeClass(Arguments &&... arguments): 
     TupleConstructor<Components>(
      std::forward<Arguments>(arguments), 
      typename MakeSequence<std::tuple_size<Arguments>::value>::type{} 
     )... 
    {} 
}; 

int main() 
{ 
    CompositeClass<ComponentA, ComponentB> composite{ 
     std::tuple<int &&, int &&>(100,100), 
     std::tuple<const char *>("Hello World!") 
    }; 

不過,我一直無法弄清楚如何從CompositeClass構造去掉兩個元。如何才能做到這一點?

回答

2

看來,如果你在灑滿水的地方減少一點點,你應該沒問題!參數包沒有特別的特別之處:它們只是展開成逗號分隔列表。也就是說,如果你改變你的代碼,成爲下面你應該確定:

template <typename... Bases> 
struct CompositeClass: public Bases... { 
    template <typename... Arguments> 
    CompositeClass(Arguments&&... arguments): 
     Bases(std::forward<Arguments>(arguments))... 
    {} 
}; 

除了在初始化列表的前面加上一個冒號,我只去掉一些多餘的「...」。只要所有模板參數實際上都是類類型,並且只要它們碰巧不同,就可以工作。顯然,不是類的類型不能用作基礎。如果您需要多次使用相同類型的基礎,則需要間接繼承它們,以便爲其提供一個數字的輔助類型。生成數字有點棘手,前幾次你做,但沒有什麼真正奇蹟般的。

在編輯的問題上進行擴展:您的意思是,您想將參數列表傳遞給每個單獨的基類構造函數?如果可以將std:tuple<...>作爲參數傳遞給您的CompositeClass,這也是可行的。實質上,您需要將每個std::tuple<...>轉換爲參數列表。這也需要產生所述指數。至少我會以一個以std::tuple<...>爲參數的輔助基礎開始,並將這些成員作爲參數轉發給基礎。這將使用類似的東西,上面的代碼爲CompositeClass和主要的竅門是在輔助類:

template <int... Numbers> struct Sequence {}; 
template <int N> struct MakeSequence; 

template <typename Base> 
struct AuxiliaryBase: Base { 
    template <typename Tuple, int... Numbers> 
    AuxiliaryBase(Tuple&&, Sequence<Numbers...> const&); 
}; 

template <typename... Bases> 
struct CompositeClass: public AuxiliaryBase<Bases>... { 
    template <typename... Args> 
    CompositeClass(Args&&... arguments): 
     AuxiliaryBase<Bases>(std::forward<Args>(arguments), 
           typename MakeSequence<std::tuple_size<Args>::size>())... 
    {} 
}; 

貫徹AuxiliaryBase構造本質上要求有創建整數從0的序列設施std::tuple_size<Tuple>::value。這需要調整一下,但絕對可行。爲了使它們可用,傳入一個輔助參數(我不確定是否可以避免這種情況;好吧,如果應該避免這種情況,它可能與std::tuple<...>打包在一起)。有了這個,基類的構造是相當直接的:

template <typename Base> 
    template <typename Tuple, int... Numbers> 
    AuxiliaryBase<Base>::AuxiliaryBase(Tuple&& tuple, Sequence<Numbers...> const&): 
     Base(std::get<Numbers>(tuple)...) 
    {} 

我還沒有測試過,但沿着這些行應該實際上工作。這個版本沒有做的是std::tuple<...>中的成員的完美轉發:爲此,您需要一個變體std::forward<>(),它帶有三個參數,它們使用外部類型的引用限定來確定哪種引用需要轉發該成員。我沒有嘗試過,但它也可能是一個有趣的練習。

我沒試過編譯這個特殊的例子,但我肯定做了這樣的事情在過去的:如果你看的slides因爲我在2010ACCU會議給了演講,你會發現如何將所有的細節要做到這一點(包括如何創建一個整數序列;實際上這很短)。

+0

使用這個CompositeClass,我需要使用元組來傳遞多個參數給任何一個基類。我已經更新了我的問題,希望能夠展示我嘗試實現的效果。 – Timesquare 2012-02-01 23:18:11

+0

有沒有什麼辦法可以在不使用元組的情況下構造'CompositeClass'並仍然將參數傳遞迴組件構造函數? – Timesquare 2012-02-02 02:34:20

+0

當然。然而,你需要一些方法來確定在編譯時哪些參數傳遞到哪個基地。您可以使用例如一個特殊的課程,然後你檢測爲分隔符。或者是型特質部隊基地。爲了使事情更簡單,我可能會創建一個輔助元組,但用戶不需要這樣做。問題是:你想知道每個基地有多少個參數? – 2012-02-02 07:29:29

相關問題