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

时间:2012-04-23 18:33:13

标签: 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&&";
}
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());
}

std::forward按预期工作。当我实现我自己的没有身份的转发函数时,会出现有趣的行为:

template <typename T> T&& MyForward(T& t)
{
   return ((T&&)t);
}

在外部用std::forward替换MyForward会得到完全相同的结果!这种行为引出了为什么要使用身份的问题?

编译器VS2010

更新1:参考防止类型扣除

AFAIK,特殊类型扣除规则仅在T&amp;&amp;上激活。请注意forward forward(typename identity<T>::type& t)的定义。参数类型只有一个&amp ;.实际上,在我将MyForward更改为使用标识并省略(T&amp;&amp;)转换后,该示例无法编译。从表面上看,从左值到右值的铸造似乎是向前发展的。

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

2 个答案:

答案 0 :(得分:13)

remove_reference<T>identity在草稿的旧版本中,但已更改为remove_reference)用于防止类型扣除:std::forward 仅< / em>使用显式类型参数。否则将编译以下内容:

std::forward(t)

......但它不会做正确的事。

关于左值/右值的问题,请注意two overloads of std::forward:一个用于左值,另一个用于右值。

实际上,给出的MyForward实现更像std::move:它将左值变为右值(不同之处在于移动也接受rvalues)。

答案 1 :(得分:0)

我在VS 2010中检查了forwardidentity的定义。MyForwardforward之间的唯一区别是您使用T&参数,他们使用typename identity<T>::type&参数。而identity<T>::type只是T

这种差异最重要(也许也是唯一)的影响是,要使用他们的forward,必须明确指定模板参数,同时可以从调用中推导出MyForward的模板参数。