转发一个转发引用的个别成员

4

我有一个可能通过其成员移动通用参数的函数。以下选项哪个更正确:

  1. This seems the more natural but it is strange because the argument is potentially moved twice [a], which is odd because the object can become invalid.

    template<class T> 
    void fun(T&& t){
        myhead_ = std::forward<T>(t).head_;
        myrest_ = std::forward<T>(t).rest_;
    }
    
  2. This can't be incorrect but it may not be moving anything.

    template<class T> void fun(T&& t){
        myhead_ = std::forward<decltype(t.head_)>(t.head_);
        myrest_ = std::forward<decltype(t.rest_)>(t.rest_);
    }
    
  3. This seems correct but too much code.

    template<class T> void fun(T& t){
        myhead_ = t.head_;
        myrest_ = t.rest_;
    }
    template<class T> void fun(T&& t){
        myhead_ = std::move(t.head_);
        myrest_ = std::move(t.rest_);
    }
    

[a] 此声明是不正确的,如@Angew指出,它只是看起来像被移动了两次。与std::move类似,std::forward实际上并不会移动任何东西。最多只会移动成员(由后续操作decltype(myhead)::operator=完成,但这正是目标所在。)

1个回答

3

您的第一段代码完全正常:

template<class T> 
void fun(T&& t){
    myhead_ = std::forward<T>(t).head_;
    myrest_ = std::forward<T>(t).rest_;
}

这是因为该标准保证在执行a.ba是xvalue(例如转发的rvalue引用)时,a.b的结果也是exvalue(即可以被移动)。还要注意std::forwardstd::move本身并不会进行任何实际的移动,它们只是类型转换。因此,在您的代码中两次从t移动是没有风险的。


第二种解决方案永远不会移动,因为t.head_是一个左值(因为t是一个左值)。你需要在decltype内部使用std::forward。然而,我已经再次检查了标准,并发现整个过程都是不必要的。 - Angew is no longer proud of SO
很棒,您可能会对这个相关案例感兴趣。https://dev59.com/zFUM5IYBdhLWcg3wY_a2#48916134,其中涉及成员函数而不是成员,但思路是相同的。 - alfC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接