Ответ 1
почему существует специализация для ссылки lvalue и rvalue?
Если существовал только основной шаблон, то выполните:
remove_reference<int&>::type
Дала бы вам:
int&
И делать:
remove_reference<int&&>::type
Дала бы вам:
int&&
Это не то, что вы хотите. Специализации для ссылок lvalue и ссылок rvalue позволяют дестать &
и &&
, соответственно, из аргумента типа, который вы передаете.
Например, если вы делаете:
remove_reference<int&&>
Тип int&&
будет соответствовать шаблону, указанному специализацией T&&
, с T
int
. Поскольку специализация определяет псевдоним типа type
как T
(в данном случае int
), делая:
remove_reference<int&&>::type
Дает вам int
.
Не могли бы вы объяснить, как, почему мы передаем
remove_reference<t>::type&&
вmove
?
Это потому, что если move()
были определены следующим образом:
template<typename T>
T&& move(T&& t) { ... }
// ^^^
// Resolves to X& if T is X& (which is the case if the input has type X
// and is an lvalue)
Тогда возвращаемый тип будет X&
, если аргумент move()
является lvalue типа X
(что так называемые "универсальные ссылки" ). Мы хотим убедиться, что возвращаемый тип всегда является ссылкой rvalue.
Цель move()
- дать вам значение rvalue, независимо от того, что вы передаете на вход. Поскольку вызов функции для функции, тип возврата которой является ссылкой rvalue, является rvalue, мы действительно хотим, чтобы move()
всегда возвращал ссылку rvalue.
Вот почему мы делаем remove_reference<t>::type&&
, потому что добавление &&
к типу без ссылки всегда гарантирует получение ссылочного типа rvalue.
Также вы могли бы указать способ, по которому я могу узнать и распечатать, что такое тип?
Я не уверен, что вы подразумеваете под "печатью" здесь. Я не знаю, как переносить имя типа в строку (независимо от того, как вы получите этот тип).
Если ваша цель - удостовериться, что rvalue была передана, с другой стороны, вы можете использовать статическое утверждение, например:
#include <type_traits>
template<typename T>
void foo(T&&)
{
static_assert(!std::is_reference<T>::value, "Error: lvalue was passed!");
// ...
}
который полагается на то, что когда передается lvalue типа X
, T
будет выведено как X&
.
Вы также можете использовать эквивалентное ограничение SFINAE, если вы хотите произвести сбой замены:
#include <type_traits>
template<typename T, typename std::enable_if<
!std::is_reference<T>::value>::type* = nullptr>
void foo(T&&)
{
// ...
}