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)
}
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.
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...);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With