Разница между реализацией std::forward

Недавно я пытался понять семантику перемещения и задал вопрос.

Вопрос уже обсуждался здесь.

Я реализовал первый вариант и проверил, возвращает ли он l-значение или r-значение:

#include <iostream>
using namespace std;

template <typename T>
T&& my_forward(T&& x) {
    return static_cast<T&&> (x);
}

int main() {
    int a = 5;
    &my_forward(a); // l-value
    return 0;
}

Поэтому, если я передаю l-значение, он возвращает l-значение (компилируется, потому что я могу взять адрес из l-значения), и если я это сделаю:

&my_forward(int(5)); // r-value with int&& type

Мой код не компилируется, потому что my_forward вернул r-значение. В приведенном выше вопросе они говорят, что разница между этой реализацией и стандартной (с std::remove_reference и 2 различными аргументами с & и && соответственно) заключается в том, что моя реализация возвращает l-значение все время, но, как я показал это возвращает и r-значение, и l-значение.

Поэтому мне интересно, почему я не могу реализовать std::forward таким образом? В каких конкретных случаях он будет отличаться от стандартного? Кроме того, почему я должен указать T как шаблон и не могу позволить ему определять себя с типом аргумента?

2 ответа

Решение

Попробуйте использовать его как std forward в реальном контексте. У тебя не работает;

void test(std::vector<int>&&){}

template<class T>
void foo(T&&t){
  test(my_forward<T>(t));
}

foo( std::vector<int>{} );

Выше не компилируется. Это с std::forward,

Ваш форвард не делает ничего полезного, кроме продления срока действия ссылки на блок. В то же время, std::forward является условным std::move,

Все с именем является lvalue, но вперед перемещает rvalue ссылки с именами.

Rvalue ссылки с именами являются lvalues.

К сожалению, захват адреса не является полезной операцией в вашем контексте, потому что он смотрит на неправильный тип категории значений:

  • Вы можете взять адрес glvalue, но не prvalue. Glvalue представляет "местоположение" (т.е. где находится объект), prvalue представляет "инициализацию" (т.е. какое значение имеет объект).

  • Вы можете красть ресурсы из значения, но не из значения. Ссылки Lvalue связываются с lvalues, ссылки rvalue связываются с rvalue. Точка std::forward должен приводить аргумент к rvalue, когда было предоставлено rvalue, и к lvalue, когда было предоставлено lvalue.

когда std::forward возвращает значение rvalue, фактически оно возвращает значение xvalue, а значения xvalue являются одновременно значениями rvalue и glvalues:

                    lvalue       f() for "T& f();",   decltype(f()) is T&
                  /
          glvalue
        /         \
  value             xvalue       f() for "T&& f();",  decltype(f()) is T&&
        \         /
           rvalue
                  \
                    prvalue      f() for "T f();",    decltype(f()) is T
Другие вопросы по тегам