Perfect Forwarding¶
Universal References? Forwarding References? REALLY?¶
This is a good ol’ function that takes an rvalue reference (to a
std::string
for that matter):
void function(std::string&& s) { ... }
This is a function template, parameterized with type T
, that
takes a universal reference - a.k.a. forwarding reference:
template <typename T>
void function(T&& param) { ... }
Universal Reference? Binds To Lvalues?¶
RValue references
A function taking an rvalue reference cannot take an lvalue
Reason: if it did, it could do harm to something the caller might still want to use
#include <string>
void function(std::string&& rvref) {}
int main()
{
std::string lvalue;
function(lvalue);
return 0;
}
c++11-rvalue-reference.cpp:10:14: error: cannot bind rvalue reference of type ‘std::string&&’ {aka ‘std::__cxx11::basic_string<char>&&’} to lvalue of type ‘std::string’ {aka ‘std::__cxx11::basic_string<char>’}
10 | function(lvalue);
| ^~~~~~
c++11-rvalue-reference.cpp:3:29: note: initializing argument 1 of ‘void function(std::string&&)’
3 | void function(std::string&& rvref)
| ~~~~~~~~~~~~~~^~~~~
But: function templates share the same syntax to mean something completely different ⟶ UNIVERSAL REFERENCES
#include <iostream>
template<typename T>
void function(T&& t)
{
std::cout << " accepted" << std::endl;
}
int main()
{
std::cout << "passing lvalue" << std::endl;
std::string lvalue;
function(lvalue);
std::cout << "passing rvalue reference" << std::endl;
function(std::move(lvalue));
return 0;
}
$ ./c++11-universal-reference
passing lvalue
accepted
passing rvalue reference
accepted
Enter Forwarding¶
Universal references accept many variations (sigh)
⟶ how can those be differentiated? Forwarded to other functions?
#include <iostream>
#include <string>
void lo_function(const std::string&)
{
std::cout << " lo_function(const std::string&)" << std::endl;
}
void lo_function(std::string&&)
{
std::cout << " lo_function(std::string&&)" << std::endl;
}
template <typename T>
void function(T&& t)
{
lo_function(std::forward<T>(t));
}
int main()
{
std::cout << "passing lvalue" << std::endl;
std::string lvalue;
function(lvalue);
std::cout << "passing rvalue reference" << std::endl;
function(std::move(lvalue));
return 0;
}
$ ./c++11-universal-reference-forward
passing lvalue
lo_function(const std::string&)
passing rvalue reference
lo_function(std::string&&)