I know that the second overload of std::foward
template< class T >
constexpr T&& forward( std::remove_reference_t<T>&& t ) noexcept;
is used for values (as stated by Howard Hinnant in his answer: How does std::forward receive the correct argument?)
There is an example of when this overload is used at cppreference.com (that is also mentioned in How does std::forward receive the correct argument? by Praetorian):
- Forwards rvalues as rvalues and prohibits forwarding of rvalues as lvalues This overload makes it possible to forward a result of an expression (such as function call), which may be rvalue or lvalue, as the original value category of a forwarding reference argument.
For example, if a wrapper does not just forward its argument, but calls a member function on the argument, and forwards its result:
// transforming wrapper template<class T> void wrapper(T&& arg) { foo(forward<decltype(forward<T>(arg).get())>(forward<T>(arg).get())); }
where the type of arg may be
struct Arg { int i = 1; int get() && { return i; } // call to this overload is rvalue int& get() & { return i; } // call to this overload is lvalue };
I really don't get this example. Why is the outer forward forward<decltype(forward<T>(arg).get())>
even needed? Cppreference states: "This overload makes it possible to forward a result of an expression (such as function call), which may be rvalue or lvalue, as the original value category of a forwarding reference argument."
As an example
void func(int& lvalue)
{
std::cout << "I got an lvalue!" << std::endl;
}
void func(int&& rvalue)
{
std::cout << "I got an rvalue!" << std::endl;
}
template <typename T>
T&& myForward(typename std::remove_reference_t<T>& t)
{
return static_cast<T&&>(t);
}
struct foo
{
int i = 42;
int& get()& { return i; }
int get()&& { return i; }
};
template <typename T>
void wrapper(T&& t)
{
func(myForward<T>(t).get());
}
int main()
{
foo f;
wrapper(f);
wrapper(foo());
return 0;
}
prints
"I got an lvalue!" "I got an rvalue!"
just fine without the outer forward while it also forwards the "result of an expression [...] as the original value category of a forwarding reference argument." It does not even need the second overload of std::forward. This overload is only necessary when calling func like so
func(forward<decltype(forward<T>(t).get())>(forward<T>(t).get()));
Still, I can't wrap my head around why anyone would need to add the outer forward. Any help is greatly appreciated.
Aucun commentaire:
Enregistrer un commentaire