首页 > 解决方案 > 转发转发引用的单个成员

问题描述

我有一个函数可能会移动一个通用参数,但通过它们的成员。这些选项中哪个更正确:

  1. 这看起来更自然,但很奇怪,因为参数可能会移动两次 [a],这很奇怪,因为对象可能会变得无效。

    template<class T> 
    void fun(T&& t){
        myhead_ = std::forward<T>(t).head_;
        myrest_ = std::forward<T>(t).rest_;
    }
    
  2. 这不可能是不正确的,但它可能不会移动任何东西。

    template<class T> void fun(T&& t){
        myhead_ = std::forward<decltype(t.head_)>(t.head_);
        myrest_ = std::forward<decltype(t.rest_)>(t.rest_);
    }
    
  3. 这似乎是正确的,但代码太多。

    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::forward(like std::move) 实际上并没有移动任何东西。最多移动成员(通过后续操作decltype(myhead)::operator=,但这正是目标。)

标签: c++11move-semanticsclass-membersforwarding-reference

解决方案


您的第一个代码非常好:

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

那是因为标准保证当做a.ba是一个xvalue(例如一个转发的右值引用)时,结果a.b也是一个exvalue(即可以被移出)。还要注意,std::forward不要std::move自己做任何实际的移动,它们只是演员表。t因此,在您的代码中从两次移动是没有风险的。


推荐阅读