繁体   English   中英

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

[英]Combination of variadic templates and multiple inheritance

为了学习关于可变参数模板的一两件事,我偶然发现了这个(希望不是那个实际的)问题。 我有以下示例代码:

#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";
    }
}

这里最初的问题是:如何将构造函数参数传递给多个基类。 只使用可变参数模板参数会限制我每个基类一个参数。 但是,如果我希望每个基类有一个可变数量的参数,那么我能想到的最聪明的事情就是使用“旧的”元组作为一种方法作弊。

显然,这个“解决方案”有一点需要注意,A,B,C中间类是构造和移动/复制的,因此每次单独调用Root构造函数。 使用具有固定基类数的真实基类构造函数将导致Root :: Root被调用一次(好吧,仍然存在钻石问题......)。

我的问题是:你有任何想法如何更优雅地解决这个问题(除了明显的解决方案,以避免可变的多重继承)。

请记住,这个问题更具有学术性质,所以“为什么不告诉我们你想要解决的真正问题呢?” 问题毫无意义。

您可以使用辅助类来执行各个基础的初始化。 (它不是我最初调用它的包装器;它不使用聚合而是继承。)

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))...
    {}
};

实例

暂无
暂无

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

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