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)