std:: remove referencia explicada?


Vi posibles implementaciones para std::remove_reference como se indica a continuación

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;};   

¿Por qué hay especializaciones para lvalue y rvalue reference? ¿No será suficiente la plantilla general y eliminará la referencia? Estoy confundido aquí porque en la especialización T& o T&& si trato de usar ::type todavía debería obtener T& o T&& respectivamente, ¿verdad?

¿Podrías explicar cómo, por qué lanzamos a remove_reference<t>::type&& en movimiento? (es porque el parámetro se nombra así que será tratado como un lvalue dentro de la función mover?).

Además, ¿podría señalar una forma en la que pueda averiguar e imprimir cuál es el tipo? por ejemplo, si es un rvalue de tipo int entonces debería ser capaz de imprimir que int&& se pasó? (He estado usando std::is_same para comprobar pero manualmente.)

Gracias por su tiempo.

Author: kvantour, 2013-06-08

2 answers

¿Por qué hay especializaciones para lvalue y referencia rvalue?

Si solo existiera la plantilla primaria, entonces haciendo:

remove_reference<int&>::type

Te daría: {[34]]}

int&

Y haciendo:

remove_reference<int&&>::type

Te daría: {[34]]}

int&&

Que no es lo que quieres. Las especializaciones para referencias lvalue y referencias rvalue permiten eliminar & y &&, respectivamente, del argumento type que se pasa.

Por ejemplo, si están haciendo:

remove_reference<int&&>

El tipo int&& coincidirá con el patrón especificado por la especialización T&&, siendo T int. Dado que la especialización define el tipo alias type como T (en este caso, int), haciendo:

remove_reference<int&&>::type

Te dará int.

¿Podrías explicar cómo, por qué echamos a remove_reference<t>::type&& en move?

Eso es porque si move() se definieran de la siguiente manera:

    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)

Entonces el tipo devuelto será X& si el argumento de move() es un lvalue de tipo X (así es como las llamadas "referencias universales"). Queremos asegurarnos de que el tipo devuelto sea siempre una referencia rvalue.

El propósito de move() es devolverle un rvalue, sin importar lo que pase en la entrada. Dado que una llamada a una función cuyo tipo de retorno es una referencia rvalue es un rvalue, realmente queremos move() devolver siempre una referencia rvalue.

Por eso lo hacemos remove_reference<T>::type&&, porque anexando && a un siempre se garantiza que el tipo sin referencia produzca un tipo de referencia rvalue.

También podría señalar una manera por la cual puedo averiguar e imprimir cuál es el tipo?

No estoy seguro de lo que quiere decir con "imprimir" aquí. No hay una forma portátil que conozco de convertir el nombre de un tipo en una cadena (no importa cómo obtengas ese tipo).

Si su objetivo es asegurarse de que se pasó un rvalue, por otro lado, podría usar una aserción estática como así:

#include <type_traits>

template<typename T>
void foo(T&&)
{
    static_assert(!std::is_reference<T>::value, "Error: lvalue was passed!");
    // ...
}

Que se basa en el hecho de que cuando se pasa un lvalue de tipo X, T se deducirá que es X&.

También podría usar una restricción SFINAE equivalente, si solo desea producir un error de sustitución:

#include <type_traits>

template<typename T, typename std::enable_if<
    !std::is_reference<T>::value>::type* = nullptr>
void foo(T&&)
{
    // ...
}
 37
Author: Andy Prowl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-08 14:22:44

Cuando se trata algún tipo como parámetro de plantilla, el compilador busca la especialización más "especializada". Si pasa un int&& a esta plantilla, el compilador usa la versión remove_reference<T&&>. La especialización general no te da lo que quieres-si pasas int&& a la especialización general, el tipo será int&&

Si desea imprimir tipo, utilice typeid(some_type).name()

 0
Author: Evgeny Eltishev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-08 14:01:18