C++11 forwarding reference
forwarding reference是function generic programming的基础:
1、auto&&
解决的是函数的返回值
2、template &&
解决的函数的参数
后面会对它们进行专门的介绍。
cppreference Reference declaration # Forwarding references (since C++11)
Forwarding references are a special kind of references that preserve the value category of a function argument, making it possible to forward it by means of std::forward. Forwarding references are either:
1)
1) function parameter of a function template declared as rvalue reference to cv-unqualified type template parameter of that same function template:
#include <utility> // std::forward
#include <iostream>
template<class T>
int g(const T&& x) // x is not a forwarding reference: const T is not cv-unqualified
{
std::cout << __PRETTY_FUNCTION__ << " " << " " << x << std::endl;
}
template<class T>
int g(const T& x)
{
std::cout << __PRETTY_FUNCTION__ << " " << " " << x << std::endl;
}
template<class T>
int f(T&& x)
{ // x is a forwarding reference
return g(std::forward<T>(x)); // and so can be forwarded
}
int main()
{
int i = 100;
f(i); // argument is lvalue, calls f<int&>(int&), std::forward<int&>(x) is lvalue
f(0); // argument is rvalue, calls f<int>(int&&), std::forward<int>(x) is rvalue
}
// g++ --std=c++11 test.cpp
NOTE: 输出如下:
int g(const T&) [with T = int] 100 int g(const T&&) [with T = int] 0
template<class T> struct A {
template<class U>
A(T&& x, U&& y, int* p); // x is not a forwarding reference: T is not a
// type template parameter of the constructor,
// but y is a forwarding reference
};
2)
2) auto&&
except when deduced from a brace-enclosed initializer list:
#include <algorithm>
#include <initializer_list>
#include <iterator>
#include <type_traits>
#include <vector> // std::vector
std::vector<int> foo()
{
return
{ 1,2,3,4};
}
std::vector<int> f()
{
return
{ 1,2,3,4};
}
template<class T>
int g(T&& x)
{ // x is a forwarding reference
return 0;
}
int main()
{
auto&& vec = foo(); // foo() may be lvalue or rvalue, vec is a forwarding reference
auto i = std::begin(vec); // works either way
(*i)++; // works either way
g(std::forward<decltype(vec)>(vec)); // forwards, preserving value category
for (auto&& x : f())
{
// x is a forwarding reference; this is the safest way to use range for loops
}
auto&& z = { 1, 2, 3 }; // *not* a forwarding reference (special case for initializer lists)
}
// g++ --std=c++11 test.cpp
See also template argument deduction and std::forward.