Почему компилятор не выбирает rvalue-reference версию `forward`? - PullRequest
2 голосов
/ 14 апреля 2020

Я написал аналогичную реализацию std::forward, надеясь выяснить, в каком случае компилятор выберет какую версию. Вопрос, кажется, никогда не выбирает rvalue-reference версию.

#include <type_traits>
#include <iostream>
#include <string>
#include <utility>

using std::string;
using std::cout;
using std::endl;
using std::remove_reference;
using std::move;

namespace explicit_return {
template <typename type> type&& forward(typename remove_reference<type>::type&  value) { cout << "cp-"; return static_cast<type&&>(value); }
template <typename type> type&& forward(typename remove_reference<type>::type&& value) { cout << "mv-"; return static_cast<type&&>(value); }
}

void print(string const & value) { cout << "c:" << value << endl; }
void print(string &  value)      { cout << "l:" << value << endl; }
void print(string && value)      { cout << "r:" << value << endl; }

template <typename type> void explicit_print(type && value) {          print(explicit_return::forward<type>(value)); }
template <typename type> void indirect_print(type && value) { explicit_print(explicit_return::forward<type>(value)); }

int main()
{
    string a("perfect");
    indirect_print(a);
    indirect_print(move(a));
    indirect_print("forward");
}

Давайте посмотрим вывод

cp-cp-l:perfect
cp-cp-r:perfect
cp-cp-r:forward

Ответы [ 2 ]

1 голос
/ 14 апреля 2020

Аргумент, который вы передаете forward<type>, является переменной, поэтому l-value.

вы можете выбрать перегрузку r-значения с дополнительным std::move или дополнительным пересылкой, когда это значение было r для пример:

template <typename type> void print_forward2(type&& value)
{
     print(explicit_return::forward<type>(explicit_return::forward<type>(value)));
}

Демонстрация

На практике я могу себе представить, что хранение аргументов в tuple и их повторное применение (один раз), что-то вместе:

print(std::forward<Ts>(std::get<Ts>(std::move(my_tuple)))...);
0 голосов
/ 14 апреля 2020

Несмотря на то, что вы объявили параметр indirect_print как type &&, его класс значений - не rvalue, а lvalue. Любой именованный объект является lvalue.

template <typename type>
void indirect_print(type && value) {
  explicit_print(explicit_return::forward<type>(value)); // `value` is lvalue here
}

Вот почему вы всегда вызываете type& версию вашей forward.

Удалите explicit_print и indirect_print и перепишите main как:

int main()
{
    string a("perfect");

    print(explicit_return::forward<std::string>(a));
    print(explicit_return::forward<std::string>(move(a)));
    print(explicit_return::forward<std::string>("forward"));
}

и вы увидите разницу:

cp-r:perfect
mv-r:perfect
mv-r:forward
...