Подтвердить что ты не робот

Std:: remove_reference объяснено?

Я видел возможные реализации для std::remove_reference ниже:

template< class T > struct remove_reference      {typedef T type;};
template< class T > struct remove_reference<T&>  {typedef T type;};
template< class T > struct remove_reference<T&&> {typedef T type;};   

Почему существует специализация для lvalue и rvalue reference? не будет ли общий шаблон сам по себе достаточным и удалить ссылку? Я запутался здесь, потому что в T& или T&& специализации, если я пытаюсь использовать ::type, мне все равно нужно получить T& или T&& соответственно?

Не могли бы вы объяснить, как, почему мы переходим к remove_reference<t>::type&& в движении? (это потому, что этот параметр назван так, что он будет рассматриваться как lvalue внутри функции перемещения?).

Также вы могли бы указать способ, с помощью которого я могу узнать и распечатать, что такое тип? например, если его rvalue типа int, то я должен иметь возможность распечатать, что int&& был передан? (Я использовал std::is_same для проверки, но вручную.)

Спасибо за ваше время.

4b9b3361

Ответ 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&&)
{
    // ...
}

Ответ 2

Когда вы обрабатываете какой-то тип в качестве параметра шаблона, компилятор ищет самую "специализированную" специализацию. Если вы передаете int && к этому шаблону компилятор использует версию remove_reference<T&&>. Общая специализация не дает вам то, что вы хотите - если вы пройдете int&& до общего специализации, тип будет int&&

Если вы хотите напечатать тип, используйте typeid(some_type).name()