How to forward packed variadic arguments

435 Views Asked by At

I have a function that accepts variadic arguments packed into a tuple

template <class... Args>
void Bottom(tuple<Args&&...> t)
{
}

Is Args&& a forwarding reference? I.e. would the rules for reference collapsing apply or am I just appending && to every argument in the pack?

And say I want to call this function from a function that certainly gets forwarding references:

template <class... Args>
void Top(Args&&... args) {
  // 1. Bottom<Pack...>();
  // 2. Bottom<Pack&&...>();
}

which syntax would be best if I don't want to alter the arguments, 1 or 2?

EDIT

I'm only using tuple to showcase a class that packs my parameters. The actual packing classes vary in different levels of the call hierarchy. The idea of using using_fwd_as_tuple is cool as a resource to find what the library does at this case.

2

There are 2 best solutions below

2
On

I'd say none. I'd use std::forward_as_tuple and let compiler do the deduction:

template <class... Args>
void Top(Args&&... args) {
  Bottom(std::forward_as_tuple(args...));
}
0
On

No, tuple<Args&&...> t are not forwarding references. They can only be present as top-level arguments.

You are not appending anything, you are attempting to match the arguments. Such function only accepts tuples (by value) which contain r-value references.

Example

#include <tuple>
using namespace std;

template <class... Args>
void Bottom(tuple<Args&&...> t)
{
}

// Type your code here, or load an example.
int main(){
    double var=0.0;

    tuple<int,double&,char&&> tup1{1,var,'c'};
    //#1
    //Bottom(tup1);

    tuple<int&&,double&&,char&&> tup2{1,0.0,'c'};
    //#2
    //Bottom(tup2);
    //#3
    Bottom(std::move(tup2));
}
  1. Does not compile since the arguments cannot be matched.
  2. Does not compile either. Eventhough the arguments do match, the tuple itself is passed by value, in this case by copy and the copy constructor is deleted in presence of r-value tuple members.
  3. Moving is fine, this instantiates this template:
    template<>
    void Bottom<int, double, char>(std::tuple<int &&, double &&, char &&> t)
    {
    }