Передача в функцию rvalue значения
Читал сегодня достаточное количество статей на хабре про rvalue ссылки и семантику перемещения. Вроде бы все понял, но наткнулся на данный пример:
template<class T, class Arg>
T* make_raw_ptr(Arg &&arg)
{
return new T(arg);
};
При передаче rvalue значения, а точнее make_raw_ptr(A()), при создании нашего объекта T в функции будет вызван конструктор копирования, поскольку arg является lvalue ссылкой. Но почему arg не rvalue ссылка, ведь при передаче аргумента в функцию, Arg = Type, а значит, Type&& arg, вследствие чего, должен быть вызван конструктор перемещения, а не копирования. К сожалению, не могу понять свою ошибку. Помогите разрешить данный вопрос.
Ответы (1 шт):
arg - это rvalue ссылка, а rvalue ссылка это lvalue. как пример:
std::string &&str = std::string("Hello");
std::string *psrt = &str;
str — lvalue, хотя его тип rvalue-ссылка. Это было сказано в указанном в вопросе примере. Соответственно, в конструктор T передается lvalue, а значит, вызовется конструктор копирования, а не перемещения. Для вызова конструктора перемещения при передаче в функцию rvalue необходимо воспользоваться std::forward или:
template<class T>
T&& my_forward(T& a)
{
return static_cast<T&&>(a);
}
template<class T, class Arg>
T* make_raw_ptr(Arg &&arg)
{
return new T(my_forward<Arg>(arg));
};
При передаче rvalue функция my_forward примет следующий вид:
template<class T>
Type&& my_forward(Type& a)
{
return static_cast<Type&&>(a);
}
поскольку универсальная ссылка при передаче в неё rvalue параметр T = Type. Следовательно, rvalue ссылка arg передастся по ссылке, как lvalue, и, my_forward вернет rvalue ссылку. При передаче же lvalue Arg в make_raw_ptr будет эквивалентно Type&. Тогда my_forward:
template<class T>
Type& && my_forward(Type& & a)
{
return static_cast<Type& &&>(a);
}
что равно:
template<class T>
Type& my_forward(Type& a)
{
return static_cast<Type&>(a);
}
в итоге чего, нам вернется обычная ссылка. Если я где-то не прав, подправьте в комментариях, спасибо.