有没有可能创建一个没有元组的复合构造函数?

时间:2012-02-01 22:14:28

标签: c++ templates constructor c++11 variadic-templates

我知道我可以将元组的参数包扩展到基类的可变参数模板 像这样:

#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,none传递给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构造函数中删除这两个元组。怎么办呢?

1 个答案:

答案 0 :(得分:2)

看来,如果你在整个地方洒下一些时间,你应该没问题!参数包并不特别特别:它们只是扩展为逗号分隔列表。也就是说,如果您将代码更改为下面的代码,那么您应该没问题:

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

除了在初始化列表前添加冒号外,我只删除了一些多余的&#34; ...&#34;。只要所有模板参数实际上是类类型并且只要它们恰好不同,这就可以正常工作。显然,不属于类的类型不能用作基础。如果你需要多次基本相同的类型,你需要间接地继承它们为什么一个辅助类型给它们一个数字。生成这些数字有点棘手,你最初几次这样做,但也没有真正神奇的。

扩展已编辑的问题:您的意思是,您希望将参数列表传递给每个基类构造函数?如果可以将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的构造函数基本上要求有一个工具创建从0std::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我在ACCU会议上发表的演示文稿2010您将找到有关如何执行此操作的所有详细信息(包括如何创建一个整数序列;实际上非常简短。)