我正在阅读新C++概述(C++ 11/14)(仅限PDF),在幻灯片288中它给出了一个实现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.
}
Run Code Online (Sandbox Code Playgroud)
然后在文本中给出另一个实现:
通常的std :: forward实现是:
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); }
Run Code Online (Sandbox Code Playgroud)
有什么不同?为什么后者通常是实施?
考虑:
void g(int&);
void g(int&&);
template<class T>
void f(T&& x)
{
g(std::forward<T>(x));
}
int main()
{
f(10);
}
Run Code Online (Sandbox Code Playgroud)
由于id-expression x是一个左值,并且std::forward对于左值和右值有重载,为什么调用不能绑定到std::forward需要左值的重载?
template<class T>
constexpr T&& forward(std::remove_reference_t<T>& t) noexcept;
Run Code Online (Sandbox Code Playgroud) 实现std::move基本上如下:
template<typename T>
typename std::remove_reference<T>::type&&
move(T&& t)
{
return static_cast<typename std::remove_reference<T>::type&&>(t);
}
Run Code Online (Sandbox Code Playgroud)
请注意,参数std::move是通用引用(也称为转发引用,但我们不在此处转发).也就是说,你可以std::move使用左值和左值:
std::string a, b, c;
// ...
foo(std::move(a)); // fine, a is an lvalue
foo(std::move(b + c)); // nonsense, b + c is already an rvalue
Run Code Online (Sandbox Code Playgroud)
但是,由于整个观点std::move都是为了施展到一个rvalue,为什么我们甚至允许std::movervalues呢?如果std::move只接受左值,那会不会更有意义?
template<typename T>
T&&
move(T& t)
{
return static_cast<T&&>(t);
}
Run Code Online (Sandbox Code Playgroud)
然后,无意义的表达式std::move(b + c)将导致编译时错误.
std::move对于初学者来说,上面的实现也会更容易理解,因为代码完全按照它的样子执行:它需要一个左值并返回一个右值.您不必了解通用引用,引用折叠和元函数.
那么为什么std::move设计同时采用左值和左值?