简体   繁体   中英

Variadic template constructor with multiple parameters packs

I have read this , this , this and many others... but none of these posts answers or is applicable to my specific problem.

I have a struct X with a variadic template constructor:

struct X
{
    template<typename... T>
    X(T... t)   { /*...*/ }
};

And I have a structure Y that contains two objects of type X . I would like to define a template constructor for Y , allowing to properly initialize both members of type X with distinct parameters list, ie something that looks like the following code (which obviously does not work):

struct Y
{
    template<typename... U, typename... V>
    Y(U&&... u, V&&... v)                                // this does not work
        : x1(std::forward(u)...), x2(std::forward(v)...) // this is was I need to do
        {}

    X x1, x2;
};

How could I do that, using wrappers, tuples or any suitable metaprogramming machinery ? A C++14 solution is acceptable.

Bog-standard index_sequence trick.

struct Y
{
private:
    template<typename... U, typename... V,
             std::size_t... UIs, std::size_t... VIs>
    Y(std::tuple<U...>&& u, std::tuple<V...>&& v,
      std::index_sequence<UIs...>, std::index_sequence<VIs...>)
        : x1(std::get<UIs>(std::move(u))...), 
          x1(std::get<VIs>(std::move(v))...)  
        {}
public:
    template<typename... U, typename... V>
    Y(std::tuple<U...> u, std::tuple<V...> v)
        : Y(std::move(u), std::move(v),
            std::index_sequence_for<U...>{},
            std::index_sequence_for<V...>{})
        {}

    X x1, x2;
};

In C++17, just use make_from_tuple :

struct Y
{
public:
    template<typename... U, typename... V>
    Y(std::tuple<U...> u, std::tuple<V...> v)
        : x1(std::make_from_tuple<X>(std::move(u))),
          x2(std::make_from_tuple<X>(std::move(v)))
        {}

    X x1, x2;
};

Using a tuple is a big overhead, since it already require from X to be moveable/copyable, you can use that constraint directly, and get the most readable code ever:

struct Y
{
    Y(X && _x1, X && _x2)                        
        : x1(std::move(_x1)), x2(std::move(_x2)) 
        {}

    X x1, x2;
};

And in code just write:

Y y(X(args_x1...), X(args_x2...));

Or if X has implicit constructor:

Y y({args_x1...}, {args_x2...});

SampleCode

The more interesting problem is, what if X is not moveable/copyable, but this is out of the scope ;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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