reference collapsing and and tuples

186 Views Asked by At

I'm trying to convert a parameter pack into references, because some arguments to my function can be a mix of r-/l- values. The function in question:

//must return tuple
template <typename ...U>
std::tuple<U...> input(const char* format, U ...args) {
    std::tuple<U...> t = std::tuple<U...> (args...);
    //other code....
}

There is some test code that I can't touch... This will call my function:

template <typename... U>
std::tuple<U...> test_input(const char* fmt, U &&...inp) {
    input(fmt, std::forward<U>(params)...);
    //other stuff...
}

And 2 test objects (also untouchable) which have deleted copy/move constructors A() and B(). as in:

A(const A &) = delete;            //same for B
A &operator=(const A &) = delete; //same for B

If I call the function, as is, I'll get "deleted copy-constructor" or "deleted constructor" errors. For example:

test_input("blah blah", 1, i, "a", std::string("a"), A(123) B("string"));

The problem is that it can be any mix of r-/l-values and I don't know how to convert them to all be references

I understand that I need a reference to the arguments. I've tried using std::forward, std::forward_as_tuple, std::make_tuple, as well as changing the second parameter to input to be U & ...args and U &&...args

I also understand that I need to use reference collapsing:

  • A& & becomes A&
  • A& && becomes A&
  • A&& & becomes A&
  • A&& && becomes A&&

I tried to use the first and third rules to convert anything to a type of A&, but I still get errors such as: call to deleted constructor of 'B' and expects an l-value for 2nd argument

In case my question wasn't clear - How do I convert args, the second argument of input, to a tuple of references?

1

There are 1 best solutions below

1
On BEST ANSWER

I think you want to do something like this:

#include <tuple>
#include <string>

//must return tuple
template <typename ...U>
std::tuple<U&&...> input(const char*, U&&...args) {
    return std::tuple<U&&...>(std::forward<U>(args)...);
    //other code....
}

template <typename... U>
std::tuple<U&&...> test_input(const char* fmt, U &&...inp) {
    return input(fmt, std::forward<U>(inp)...);
    //other stuff...
}

struct A {
    A(int) { }
    A(const A &) = delete;            //same for B
    A &operator=(const A &) = delete; //same for B
};

struct B {
    B(const char *) { }
    B(const B &) = delete;            //same for B
    B &operator=(const B &) = delete; //same for B
};

int main() {
    int i = 1;
    test_input("blah blah", 1, i, "a", std::string("a"), A(123), B("string"));
}

[live demo]