简体   繁体   English

可变参数模板和多重继承的组合

[英]Combination of variadic templates and multiple inheritance

For the sake of learning one or two things about variadic templates I stumbled across this (hopefully not that practical) problem. 为了学习关于可变参数模板的一两件事,我偶然发现了这个(希望不是那个实际的)问题。 I have the following example code: 我有以下示例代码:

#include <utility>
#include <tuple>
#include <iostream>

template <typename... Args>
auto args(Args&&... args) {
    return std::make_tuple(std::forward<Args>(args)...);
}

template <class C, class TupleArgs, std::size_t... Indices>
C construct_class_unpacked_(TupleArgs&& args, std::index_sequence<Indices...>) {
    return C(std::get<Indices>(std::forward<TupleArgs>(args))...);
}

template <class C, typename TupleArgs>
C construct(TupleArgs&& args) {
    return construct_class_unpacked_<C>(std::forward<TupleArgs>(args), std::make_index_sequence<std::tuple_size<typename std::decay<TupleArgs>::type>::value>());
}

struct Root {
    Root(int l) : l_(l) {
    }

    protected:
        Root() : l_(-2) {}

    public:
        int l_;
};

struct A : public virtual Root {
    A(int i, float f) : i_(i), f_(f) {}

    int i_;
    float f_;
};

struct B : public virtual Root {
    B(int j, float g) : j_(j), g_(g) {}

    int j_;
    float g_;
};

struct C : public virtual Root {
    C() : x_(1), y_(3.1) {
    }

    int x_;
    float y_;
};

template <typename Base, typename... Bases>
struct S : public Bases... {
    template <typename Arg, typename... TupleArgs>
    S(Arg&& arg, TupleArgs&&... args) : Base(std::forward<Arg>(arg)), Bases(construct<Bases>(std::forward<TupleArgs>(args)))... {
    }
};

int main (int argc, char const* argv[]) {
    {
        S<Root, A, C, B> s(4, args(2, 3.1f), args(), args(3, 5.3f));
        std::cout << s.i_ << "\n";
        std::cout << s.f_ << "\n";
        std::cout << s.j_ << "\n";
        std::cout << s.g_ << "\n";
        std::cout << s.x_ << "\n";
        std::cout << s.y_ << "\n";
        std::cout << s.l_ << "\n";
    }
}

The original problem here was: How would I pass constructor parameters to multiple base classes. 这里最初的问题是:如何将构造函数参数传递给多个基类。 Just using variadic template arguments would restrict me to one argument per base class. 只使用可变参数模板参数会限制我每个基类一个参数。 If however I wanted to have a variable number of arguments per base class the most clever thing I could come up with was to use the "old" tuple-as-a-way-around cheat. 但是,如果我希望每个基类有一个可变数量的参数,那么我能想到的最聪明的事情就是使用“旧的”元组作为一种方法作弊。

Obviously this "solution" has the caveat, that the A,B,C intermediate classes are constructed and moved/copied, therefore the Root constructor gets called each time separately. 显然,这个“解决方案”有一点需要注意,A,B,C中间类是构造和移动/复制的,因此每次单独调用Root构造函数。 Using real base class constructors with a fixed count of base classes would result in Root::Root being called exactly once (well, there's still the diamond problem...). 使用具有固定基类数的真实基类构造函数将导致Root :: Root被调用一次(好吧,仍然存在钻石问题......)。

My question is: Do you have any ideas how to solve this problem more elegantly (apart from the obvious solution to just avoid variadic multiple inheritance). 我的问题是:你有任何想法如何更优雅地解决这个问题(除了明显的解决方案,以避免可变的多重继承)。

And keep in mind that this question is more of an academic nature, so "why not tell us what real problem you want to solve?" 请记住,这个问题更具有学术性质,所以“为什么不告诉我们你想要解决的真正问题呢?” questions are quite pointless. 问题毫无意义。

You can use a helper class to perform the initialization of the individual bases. 您可以使用辅助类来执行各个基础的初始化。 (It's not a wrapper as I've originally called it; it doesn't use aggregation but inheritance.) (它不是我最初调用它的包装器;它不使用聚合而是继承。)

template<class Tuple>
auto make_index_sequence_for_tuple_expansion(Tuple&&)
{
    using decayed_tuple = typename std::decay<Tuple>::type;
    return std::make_index_sequence<std::tuple_size<decayed_tuple>::value>();
}

template<class T>
struct unpacker : T
{
    template<class Tuple, std::size_t... Is>
    unpacker(Tuple&& tuple, std::index_sequence<Is...>)
        : T( std::get<Is>(std::forward<Tuple>(tuple))... )
    {}

    template<class Tuple>
    unpacker(Tuple&& tuple)
        : unpacker( std::forward<Tuple>(tuple),
                    make_index_sequence_for_tuple_expansion(tuple) )
    {}
};

template <typename Base, typename... Bases>
struct S : public unpacker<Bases>... {
    template <typename Arg, typename... TupleArgs>
    S(Arg&& arg, TupleArgs&&... args)
        : Base(std::forward<Arg>(arg))
        , unpacker<Bases>(std::forward<TupleArgs>(args))...
    {}
};

Live example 实例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM