Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std forward implementation and reference collapsing

Tags:

c++11

in scott meyers book he mentioned an implementation for std forward that goes like this (non std conformant)

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

The question is why do we need to remove reference here?

so a typical forward usage would be in a universal reference function as follows:

template <typename T>
void f(T&& fparam)
{
    g(forward<T>(fparam));  // assume there is g function.
}

without remove reference, the forward would look like this

template <typename T>
T&& forward(T& param);

now the two cases are:

  1. fparam is rvalue in that case inside f function the T is deduced as non reference object type so the forward call take the param by lvalue reference and cast it to T&& (because T is non reference).

  2. fparam is lvalue then inside f the T is deduced as T& then forward will take (as argument) a reference to an lvalue reference (collapsing to lvalue reference) then the static cast would be T& && which is again lvalue reference.

so why do we need to remove reference from param of forward? does it have to do with disallowing deducing types maybe? can somebody maybe give a detailed explanation.

The question that is referenced as duplicate is not, the answer basically says that the std library uses remove reference but why?

like image 641
mkmostafa Avatar asked Mar 22 '17 09:03

mkmostafa


People also ask

What is reference collapsing?

Reference collapsing is the mechanism that leads to universal references (which are really just rvalue references in situations where reference-collapsing takes place) sometimes resolving to lvalue references and sometimes to rvalue references.

What is std forward?

std::forward This is a helper function to allow perfect forwarding of arguments taken as rvalue references to deduced types, preserving any potential move semantics involved.

What is a forwarding reference?

I understand that a forwarding reference is "an rvalue reference to a cv-unqualified template parameter", such as in. template <class T> void foo(T&& ); which means the above function can take both l-value and r-value reference.

Why is STD forward needed?

If you don't invoke std::forward and only do f(x) , then x will always be a lvalue, so you'll be losing move semantics when needed and may end up with un-necessary copies etc.

What is std forward used for?

That was easy; let’s look at std::forward. std::forward is used as part of perfect forwarding, where we take a bunch of arguments and want to pass them to another function. #include <utility> template <typename Fn, typename ... Args> void call(Fn fn, Args&&... args) { // Forward the arguments to the function. fn(std::forward<Args>(args)...); }

What is the difference between std::forward and std::move?

std::forward keeps the reference type of x. So: If x is an rvalue reference then std::forward is = std::move, If x is an lvalue reference then std::forward doesn’t do anything. So for the previous example of ‘wrapper’ function on func (E1 E2, ... En) - } // Awesome!! std::forward is a conditional cast but std::move is an unconditional cast.

What is forwarding reference in C++?

†The term forwarding reference derives its name from std::forward () 's name. If a function parameter of a function template is declared as an rvalue reference to cv-unqualified type template parameter of that same function template, we call it a universal reference or a forwarding reference.

What is reference collapsing in DBMS?

Reference collapsing is magic that enables Universal references to work. These rules are basically a logical AND of Lvalue ref implying ‘0’ (zero) with Rvalue ref implying ‘1’ (one) Reference Collapsing Rule#1: Lvalues are infectious. So basically in the above template examples of Univeral reference —


1 Answers

Does it have to do with disallowing deducing types maybe?

Yes, typename std::remove_reference<T>::type introduces a non-deduced context. It prevents the user from mistakenly writing...

std::forward(something)

...and forces him/her to provide an explicit template argument:

std::forward<T>(something)
like image 112
Vittorio Romeo Avatar answered Jan 02 '23 13:01

Vittorio Romeo