In C + + 11, & & is not only a logical and, but also a right-hand reference
void f(int&& i);
However, it may also be a forward reference:
template<typename T>
void g(T&& obj);
“Forwarding reference” is formerly known as “universal reference”. Its “universal” is that you can bind an lvalue to a forward reference, but not to an rvalue reference
void f(int&& i) { }
template<typename T>
void g(T&& obj) { }
int main()
{
int n = 2;
f(1);
// f(n); // error
g(1);
g(n);
}
In order to be a forwarding reference, the parameters of a function must satisfy the following requirements:
- The parameter type is T & & without const or volatile;
- T must be a template parameter for the function.
In other words, none of the parameters of the following functions are forward references:
template<typename T>
void f(const T&&);
template<typename T>
void g(typename std::remove_reference<T>&&);
template<typename T>
class A
{
template<typename U>
void h(T&&, const U&);
};
Another case is that the auto & & variable can also be a forward reference:
auto&& vec = foo();
So the best way to write a range for loop is to use auto & amp
std::vector<int> vec;
for (auto&& i : vec)
{
// ...
}
There is an exception. When auto & & L = {1, 2, 3}; is on the right side of auto & & L, the variable is STD:: initializer_ List < int > & type.
Forward reference is used to forward. Write forward reference T & & only when your intention is to forward parameters. Otherwise, it is better to write const T & and T & & as overloads (if necessary, you can also write T & and const T & & which is not commonly used; where t is a specific type rather than a template parameter).
To forward a forward reference, you need to use STD:: forward, which is defined in < utility >:
There are several possible parameters to call G:
- Int i = 1; G (I);, t is int &, call g (int &);
- Const int j = 2; G (J);, t is const int & and calls g (const int &);
- Int k = 3; G (STD:: move (k)); or G (4);, t is int (not int & & Oh!) , call g (int & &).
You may wonder why STD:: move doesn’t need < T > and STD:: forward does? Let’s start with the signature of STD:: forward
template<typename T>
constexpr T&& forward(std::remove_reference_t<T>&) noexcept;
template<typename T>
constexpr T&& forward(std::remove_reference_t<T>&&) noexcept;
When STD:: forward is called, the compiler cannot remove according to STD:: forward_ reference_ T < T > reverses t to instantiate the function template, so < T > needs to be specified manually.
But it doesn’t answer the question fundamentally, or it can lead to a new question: why is the parameter of STD:: forward not defined as T &?
The reason is very simple. T & & will eat T -, const T -, T -, and const T & (as well as corresponding volatile). It is useless to write T & after T &.
Wait a minute. Do the T & amp; arguments match T & amp; in the incoming function?
#include <iostream>
#include <utility>
void foo(int&)
{
std::cout << "int&" << std::endl;
}
void foo(const int&)
{
std::cout << "const int&" << std::endl;
}
void foo(int&&)
{
std::cout << "int&&" << std::endl;
}
void bar(int&& i)
{
foo(i);
}
int main()
{
int i;
bar(std::move(i));
}
can’t! Program output int &. The value of I in the left bar is a reference type of the function. More directly, it has a name, so it’s an lvalue.
Therefore, if STD:: forward doesn’t have a template parameter that you specify manually, it won’t be able to distinguish between T & and T & — that would be “bad forwarding,” not “perfect forwarding.”.
Finally, the implementation of STD:: forward is analyzed. The following code is from libstdc + +:
template<typename _Tp>
constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type& __t) noexcept
{ return static_cast<_Tp&&>(__t); }
template<typename _Tp>
constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
{
static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument"
" substituting _Tp is an lvalue reference type");
return static_cast<_Tp&&>(__t);
}
- Matches the first overload when the forwarding reference T & & obj binds the left value int +_ TP, that is, t is int & and returns the type_ TP & & is int & (reference folding: &, & &, & & are all folded to &, only & & & is folded to &);
- Const int & the same principle;
- When the forwarding reference binds the right value int & & to match the second overload_ TP is int, and the return type is int & &;
- Const int & the same thing.
To sum up, STD:: forward can forward perfectly.
Programmers always have to hit the wall on the stack overflow to learn something.
This article about C + + 11 template parameters “right value reference” is a forward reference to this article introduced here, more relevant C + + 11 right value reference content please search the previous articles of developeppaer or continue to browse the related articles below, I hope you can support developeppaer more in the future!