C++11:std的微妙之处::转发:身份真的有必要吗?

c++11: subtlety of std::forward: Is identity really necessary?

本文关键字:真的 身份 std C++11 转发      更新时间:2023-10-16

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

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);
}

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

编译器 VS2010

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

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

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

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

std::forward(t)

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

关于左值/右值的问题,请注意std::forward有两个重载:一个用于右值,另一个用于右值。

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

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

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