Форвард отдельных членов Форвард ссылки - PullRequest
0 голосов
/ 03 мая 2018

У меня есть функция, которая потенциально перемещает общий аргумент, но через своих членов. Какой из этих вариантов более правильный:

  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=, но это и есть цель.)

1 Ответ

0 голосов
/ 03 мая 2018

Ваш первый код в порядке:

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

Это потому, что стандарт гарантирует, что при выполнении a.b и a является значением xvalue (например, перенаправленной ссылкой на rvalue), результат a.b также является exvalue (то есть может быть перемещен из). Также обратите внимание, что std::forward и std::move не выполняют никаких фактических перемещений , они просто являются приведениями. Таким образом, нет риска перейти от t дважды в вашем коде.

...