可能的std :: forward实现之间的区别

时间:2018-04-02 15:00:36

标签: c++

我看到了std::forward的3个实施方向。

为了测试它们,我写了流动的测试:

void test(int&&){ std::cout <<"refref\n";}
void test(int&){ std::cout <<"ref\n";}

template<class T>
void foo(T&& t){
     test(fwd<T>(t));

int main (){
   auto v = 5;
   foo(5);
   foo(v);
   foo(std::move(v));
}

第一个也是最简单的是:

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

据我所知,这里的主要问题是T可以推断出来。 在这种情况下,它将始终返回Rvalue引用(T将推断为T(永远不会T&),并且不会有引用折叠)

为了解决这个问题,我们可以添加标识类:

template<typename T>
struct identity{
    typedef T type;
};

template <typename T>
T&& fwd( typename identity<T>::type t) {
   return static_cast<T&&>(t);
}

但是,我看到标准规定:

template <typename T>
T&& fwd( typename remove_reference<T>::type t) {
  return static_cast<T&&>(t);
}

两者之间有什么区别吗?

1 个答案:

答案 0 :(得分:0)

template <typename T>
T&& fwd( typename remove_reference<T>::type t) {
  return static_cast<T&&>(t);
}

这不是std::forward的正确实现。

template <typename T>
T&& fwd( typename remove_reference<T>::type& t) {
  return static_cast<T&&>(t);
}
template <typename T>
T&& fwd( typename remove_reference<T>::type&& t) {
  return static_cast<T&&>(t);
}

这两个是。

你的价值取t; std::forward始终采用右值或左值参考。 (我省略了&#39; constexpr,因为现在不重要。)

我会比较你的:

template <typename T>
T&& fwd( typename identity<T>::type t) {
  return static_cast<T&&>(t);
}

到正确的代码。

你的错误有两种。首先,如果传入非引用类型,则按值获取:

struct foo {
  foo(foo&&)=default;
  foo(foo const&)=delete;
};

foo f1;
auto f2 = fwd<foo>(f1);

这在您的版本中无法编译,因为fwd<foo>按值foo获取,因此在调用它时会尝试将f1复制到其参数中。

我们可以在某种程度上解决这个问题:

template <typename T>
T&& fwd( typename identity<T>::type&& t) {
  return static_cast<T&&>(t);
}

但现在,当你传入T=foo时,你被迫传递了一个右值。这不好。所以现在我们添加另一个重载:

template <typename T>
T&& fwd( typename identity<T>::type& t) {
  return static_cast<T&&>(t);
}

当我们通过T=foo时,我们可以使用 rvalue或左值参数。到现在为止还挺好。但是当我们通过T=foo&时会发生什么?好吧,然后第一个重载变成foo& &&变成foo&,我们被阻止接受rvalues然后使用forward将它们转换为左值。

auto f3 = fwd<foo&>( foo{} );

上述内容对std::forward是合法的,但不适用于fwd