【问题标题】:Forward individual members of a Forward reference转发转发引用的单个成员
【发布时间】:2018-10-13 11:14:25
【问题描述】:

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

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

【问题讨论】:

    标签: c++11 move-semantics class-members forwarding-reference


    【解决方案1】:

    您的第一个代码非常好:

    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::forwardstd::move 本身并没有进行任何实际的移动,它们只是演员表。因此,在您的代码中从 t 移动两次是没有风险的。

    【讨论】:

    • @alfC 第二个解决方案永远不会移动,因为t.head_ 是一个左值(因为t 是一个左值)。您需要在 decltype 中使用std::forward。然而,我后来仔细检查了标准,发现整个事情是不必要的。
    • 太棒了,您可能对这个相关案例感兴趣。 stackoverflow.com/a/48916134/225186 ,涉及成员函数而不是成员的想法是相同的。
    猜你喜欢
    • 1970-01-01
    • 2019-02-08
    • 2012-01-24
    • 1970-01-01
    • 2022-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多