13

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

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用in outer替换MyForward会得到完全相同的结果!这种行为引出了一个问题,为什么要使用身份?

编译器VS2010

更新 1:关于防止类型推断

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

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

4

2 回答 2

14

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

std::forward(t)

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

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

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

于 2012-04-23T19:08:51.303 回答
0

我检查了 VS 2010 中forward和的定义。你和他们identity的唯一区别是你使用参数,而他们使用参数。而这只是.MyForwardforwardT&typename identity<T>::type&identity<T>::typeT

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

于 2012-04-24T03:44:15.967 回答