Разница между реализацией 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