2012-02-01 40 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

相关问题