В таком шаблоне функции
template <typename T>
void foo(T&& x) {
bar(std::forward<T>(x));
}
Разве x
не является ссылкой на rvalue внутри foo
, если foo
вызывается со ссылкой на rvalue? Если foo вызывается со ссылкой lvalue, приведение в любом случае не требуется, потому что x
также будет ссылкой lvalue внутри foo
. Также T
будет выведен к типу ссылки lvalue, и поэтому std::forward<T>
не изменит тип x
.
Я провел тест с использованием boost::typeindex
и получил точно такие же типы с std::forward<T>
и без него.
#include <iostream>
#include <utility>
#include <boost/type_index.hpp>
using std::cout;
using std::endl;
template <typename T> struct __ { };
template <typename T> struct prt_type { };
template <typename T>
std::ostream& operator<<(std::ostream& os, prt_type<T>) {
os << "\033[1;35m" << boost::typeindex::type_id<T>().pretty_name()
<< "\033[0m";
return os;
}
template <typename T>
void foo(T&& x) {
cout << prt_type<__<T>>{} << endl;
cout << prt_type<__<decltype(x)>>{} << endl;
cout << prt_type<__<decltype(std::forward<T>(x))>>{} << endl;
cout << endl;
}
int main(int argc, char* argv[])
{
foo(1);
int i = 2;
foo (i);
const int j = 3;
foo(j);
foo(std::move(i));
return 0;
}
Результатом g++ -Wall test.cc && ./a.out
с gcc 6.2.0
и boost 1.62.0
является
__<int>
__<int&&>
__<int&&>
__<int&>
__<int&>
__<int&>
__<int const&>
__<int const&>
__<int const&>
__<int>
__<int&&>
__<int&&>
Изменить: я нашел этот ответ: https://stackoverflow.com/a/27409428/2640636 Судя по всему,
как только вы даете имя параметру, это lvalue.
Тогда у меня вопрос, почему было выбрано такое поведение вместо сохранения ссылок rvalue как rvalue, даже если им даны имена? Мне кажется, таким образом можно было обойти все невзгоды.
Edit2: я не спрашиваю, что std::forward
делает. Я спрашиваю, зачем это нужно.