Reputation: 113
I wrote a similar implementation of std::forward
hoping to find out in which case the compiler will pick which version. The question is it seems never pick the rvalue-reference version.
#include <type_traits>
#include <iostream>
#include <string>
#include <utility>
using std::string;
using std::cout;
using std::endl;
using std::remove_reference;
using std::move;
namespace explicit_return {
template <typename type> type&& forward(typename remove_reference<type>::type& value) { cout << "cp-"; return static_cast<type&&>(value); }
template <typename type> type&& forward(typename remove_reference<type>::type&& value) { cout << "mv-"; return static_cast<type&&>(value); }
}
void print(string const & value) { cout << "c:" << value << endl; }
void print(string & value) { cout << "l:" << value << endl; }
void print(string && value) { cout << "r:" << value << endl; }
template <typename type> void explicit_print(type && value) { print(explicit_return::forward<type>(value)); }
template <typename type> void indirect_print(type && value) { explicit_print(explicit_return::forward<type>(value)); }
int main()
{
string a("perfect");
indirect_print(a);
indirect_print(move(a));
indirect_print("forward");
}
Let's see the output
cp-cp-l:perfect
cp-cp-r:perfect
cp-cp-r:forward
Upvotes: 2
Views: 73
Reputation: 150
Despite of you have declared indirect_print
parameter as type &&
, its value class is not an rvalue, but lvalue. Any named object is lvalue.
template <typename type>
void indirect_print(type && value) {
explicit_print(explicit_return::forward<type>(value)); // `value` is lvalue here
}
That's why you're always call a type&
version of your forward
.
Remove explicit_print
and indirect_print
and rewrite main
as:
int main()
{
string a("perfect");
print(explicit_return::forward<std::string>(a));
print(explicit_return::forward<std::string>(move(a)));
print(explicit_return::forward<std::string>("forward"));
}
and you will see the difference:
cp-r:perfect
mv-r:perfect
mv-r:forward
Upvotes: 0
Reputation: 217085
Argument you pass to forward<type>
is a variable, so a l-value
.
you might have r-value overload selected with extra std::move
or extra forward when it was a r-value for example:
template <typename type> void print_forward2(type&& value)
{
print(explicit_return::forward<type>(explicit_return::forward<type>(value)));
}
In practice, I can imagine that storing arguments in tuple
and reapplying them (once), something along:
print(std::forward<Ts>(std::get<Ts>(std::move(my_tuple)))...);
Upvotes: 1