Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ having trouble storing tuple of pointers

I have an object 'S' that stores a simple tuple of pointers, which is made flexible by the use of variadic templates. There are two methods, store() and store2(). The first one (store) works fine. The second one won't compile because std::make_tuple fails with the error:

'No matching function for call to 'make_tuple'

It further adds that there is no known conversation from 'B*' to 'B*&&' for 1st argument (this error is deep in the tuple library header).

Code is here:

#include <tuple>
#include <utility>

template<typename...Rs>
struct S
{
    void store(std::tuple<Rs*...> rs)
    {
        rs_ = rs;
    }

    void store2(Rs*...rs)
    {
        rs_ = std::make_tuple<Rs*...>(rs...); // This is the guy that breaks
    }

private:
    std::tuple<Rs*...> rs_;
};

struct B
{};

struct A : S<B, B>
{};

int main()
{
    auto *b1 = new B;
    auto *b2 = new B;
    auto *a1 = new A;

    a1->store(std::make_tuple(b1, b2));   // This works
    a1->store2(b1, b2);    // How can I get this to work?
                           // (It causes an error in std::make_tuple of store2 above)
}
like image 565
user5406764 Avatar asked Jan 07 '23 04:01

user5406764


2 Answers

It's an error because make_tuple, like C++11-or-later make_pair, takes forwarding references, and when you explicitly specify template arguments that are non-references, those forwarding references become rvalue references.

So make_tuple<Rs*...> is tuple<Rs*...> make_tuple(Rs*&&...) - the parameter types are all rvalue references, which do not bind to lvalues (and rs... expands to a list of lvalues).

The whole point of these make_meow functions is to avoid having to write out explicit template arguments, so...don't write them.

like image 56
T.C. Avatar answered Jan 15 '23 07:01

T.C.


I can't explain exactly why it's an error (I suspect it's something to do with the mandatory decay), but std::make_tuple is not intended to be called with explicitly-specified template arguments (in which case you can just use std::tuple, rather it is for when you want them to be deduced).

Either of the following two works:

rs_ = std::tuple<Rs*...>(rs...);
rs_ = std::make_tuple(rs...);
like image 45
o11c Avatar answered Jan 15 '23 09:01

o11c