Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The implementation of std::forward

Tags:

c++

c++11

I'm reading Overview of the New C++ (C++11/14) (PDF only), at Slide 288 it gives an implementation of std::forward:

template<typename T>                // For lvalues (T is T&), T&& std::forward(T&& param)         // take/return lvalue refs. {                                   // For rvalues (T is T),     return static_cast<T&&>(param); // take/return rvalue refs. } 

And then gives another implemention in text:

The usual std::forward implementation is:

template<typename T> struct identity {     typedef T type; }; template<typename T> T&& forward(typename identity<T>::type&& param) {     return static_cast<identity<T>::type&&>(param); } 

What is the difference? Why is latter the usual implementation?

like image 457
songyuanyao Avatar asked Dec 16 '14 09:12

songyuanyao


People also ask

What is the use of std :: forward?

The idiomatic use of std::forward is inside a templated function with an argument declared as a forwarding reference , where the argument is now lvalue , used to retrieve the original value category, that it was called with, and pass it on further down the call chain (perfect forwarding).

What is C++ perfect forwarding?

What is Perfect Forwarding. Perfect forwarding allows a template function that accepts a set of arguments to forward these arguments to another function whilst retaining the lvalue or rvalue nature of the original function arguments.

Why does STD forward need a template parameter?

Because for std::forward to work as intended(, i.e. to faitfully pass the original type info), it is meant to be used INSIDE TEMPLATE CONTEXT, and it must use the deduced type param from the enclosing template context, instead of deducing the type param by itself(, since only the enclosing templates have the chance to ...

What is forwarding reference in C++?

When t is a forwarding reference (a function argument that is declared as an rvalue reference to a cv-unqualified function template parameter), this overload forwards the argument to another function with the value category it had when passed to the calling function.


2 Answers

The problem with the first is that you can write std::forward(x), which doesn't do what you want, since it always produces lvalue references.

The argument in the second case is a non-deduced context, preventing automatic deduction of the template argument. This forces you to write std::forward<T>(x), which is the right thing to do.

Also, the argument type for the second overload should be typename identity<T>::type& because the input to idiomatic use of std::forward is always an lvalue.

Edit: The standard actually mandates a signature equivalent to this one (which, incidentally, is exactly what libc++ has):

template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept; template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept; 
like image 59
Sebastian Redl Avatar answered Sep 22 '22 18:09

Sebastian Redl


The implementation in libc++ uses std::remove_reference and two overloads. Here is the source (after removing some macros):

template <class T> inline T&& forward(typename std::remove_reference<T>::type& t) noexcept {     return static_cast<T&&>(t); }  template <class T> inline T&& forward(typename std::remove_reference<T>::type&& t) noexcept {     static_assert(!std::is_lvalue_reference<T>::value,                   "Can not forward an rvalue as an lvalue.");     return static_cast<T&&>(t); } 

but note that in C++14, std::forward is constexpr.

like image 42
Walter Avatar answered Sep 26 '22 18:09

Walter