C++ c++;11:std::forward的微妙之处:身份真的有必要吗?

C++ c++;11:std::forward的微妙之处:身份真的有必要吗?,c++,visual-studio-2010,visual-c++,c++11,C++,Visual Studio 2010,Visual C++,C++11,我设置了一个测试用例来学习完美转发 std::string inner(const std::string& str ) { return "const std::string&"; } std::string inner(std::string& str ) { return "std::string&"; } std::string inner(const std::string&& str ) { return "const

我设置了一个测试用例来学习完美转发

std::string inner(const std::string& str ) {
return "const std::string&";
}
std::string inner(std::string& str ) {
    return "std::string&";
}
std::string inner(const std::string&& str ) {
    return "const std::string&&";
}
std::string inner(std::string&& str ) {
    return "std::string&&";
}

template <typename T> void outer(T&& t) {
  std::cout << "t: " << t << std::endl;
  std::cout << "perfect forward: " << inner(std::forward<T>(t)) << std::endl;
  std::cout << std::endl;
}

void PerfectForwarding()
{
     outer("literal");
     outer(lvalue);
     outer(constlvalue);
     outer(rvalue());
     outer(constrvalue());
}
在outer中将
std::forward
替换为
MyForward
,得到完全相同的结果!这种行为回避了一个问题:为什么使用身份

编译器VS2010

更新1:关于防止类型扣减

好的,特殊类型扣除规则仅在T&&上激活。注意forward的定义,
forward(typename-identity::type&t)
。参数类型只有一个&。事实上,在我将MyForward更改为使用identity并省略(T&&)转换之后,该示例无法编译。从表面上看,从左值到右值的转换似乎推动了前进

更新2:使用GCC 4.5在ideone.com上测试,行为相同。

remove\u reference
identity
在草稿的旧版本中,但更改为
remove\u reference
)用于防止类型推断:
std::forward
仅适用于显式类型参数。否则,将编译以下内容:

std::forward(t)
。。。但它不会做正确的事情

关于左值/右值的问题,请注意有:一个用于左值,另一个用于右值


事实上,给出的
MyForward
实现更像是:它将左值转换为右值(区别在于move也接受右值)。

我在VS2010中检查了
forward
identity
的定义。您的
MyForward
和它们的
forward
之间唯一的区别是您使用了
T&
参数,它们使用的是
typename identity::type&
参数。而
identity::type
就是
T


这种差异最重要(可能也是唯一)的影响是,要使用它们的
转发
,必须显式指定模板参数,而您的
MyForward
的模板参数可以从调用中推导出来。

您所说的“标识”是什么意思?
std::forward
remove\u reference::type
?标识的两个重载引用标识结构,即转发的参数类型:_Ty&&forward(typename identity::type&&u Arg),它必须是一些预标准签名。标准的是
T&&forward(typename remove\u reference::type&T)
(以及一个重载
&&
)。我使用VS2010编译器。它可能是编译器特定的行为。cppreference.com确实列出了forward的两个重载。@Candy:VC++2010基于N3000,N3000随
std::identity
而来;最终的C++11标准基于N3290,N3290将其删除。在VS2010中只有一个标准。它和一个一起工作。那么为什么我们需要两个呢?@CandyChiu它在VS2010上工作,因为它是在标准最终确定之前发货的。在VS2010发布和标准发布之间,规则发生了变化。我们需要两个,因为左值不会绑定到
&&
,右值不会绑定到
&
。我明白了。不幸的是,我手头没有另一个编译器来测试它。@Candy如果有帮助,运行GCC4.5。我不知道他们是如何在那里实现的,但是你可以用自己的实现进行实验。我相信它有正确的右值绑定语义。好吧,guess 4.5还不好:(FWIW,我运行GCC 4.7和clang 3.1,它的工作方式与我描述的一样。是的,如果将左值传递给外部(t&),t将被转换为右值引用类型。
std::forward(t)