I'm learning about templates and tried to implement this method:
template <typename Func, typename Left, typename Right>
void flipArgs(Func* function, Left&& leftArg, Right&& rightArg) {
function(std::forward<Right>(rightArg), std::forward<Left>(leftArg));
}
It takes a function and two parameters and calls the given function with the two parameters flipped.
It works fine with function such as:
void test1(std::string, int) {
}
When I tried this function:
template <typename T>
void test2(T&& a, int) {
}
With:
string s("test");
flip(test2<string>, 42, s);
The compiler (g++ 4.7.1) tells me:
error: cannot bind 'std::basic_string' lvalue to 'std::basic_string&&'
I thought that a function parameter such as T&&
was a special case that can bind to rvalue
and lvalue
references? What am I doing wrong?
I thought that a function parameter such as
T&&
was a special case that can bind to [rvalues and lvalues]?
It is. It basically means the template can have different instantiations for lvalues and for rvalues.
However... When you explicitly make T
be string
in test2<string>
, you are picking one particular instantiation: void test2(string&&, int)
. string&&
is no longer that special case. string&&
can only bind to string rvalues. There isn't one instantiation that binds to both rvalues and lvalues.
In general, I'd recommend against explicitly passing function template parameters (unless those are intended, like std::forward
or std::make_unique
).
In this case, you could instead force one of the instantiations that binds to lvalues. Something like flip(test2<string&>, 42, s);
, which will instantiate void test2(string&, int)
.
If you really want to pass an argument to flip
that can accept both lvalues and rvalues, you need a polymorphic function object:
struct test2 {
template <typename T>
void operator()(T&& a, int) const {
}
};
flip(test2{}, 42, s);
The key here is that the decision of which specialisation to use is not made when passing the argument, but only later on when that argument is used.
For completeness, in C++14 you can actually create anonymous polymorphic function objects with the new lambda syntax:
auto test2 = [](auto&& a, int) {};
flip(test2, 42, s);
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