¿Qué es un contexto no deducido?

4 minutos de lectura

¿Que es un contexto no deducido
Zapato

me he tropezado”¿Por qué la deducción del argumento de la plantilla no funciona aquí?” recientemente y las respuestas se pueden resumir en “Es un contexto no deducido”.

Específicamente, el primero dice que es tal cosa y luego redirige al estándar para “detalles”, mientras que el segundo cita el estándar, que es críptico por decir lo menos.

¿Puede alguien por favor explicar a los simples mortales, como yo, qué contexto no deducido es, ¿cuándo ocurre y por qué ocurre?

  • Relacionado: C++, el argumento de la plantilla no se puede deducir

    – Shafik Yaghmour

    11 de agosto de 2014 a las 14:22

1647549550 661 ¿Que es un contexto no deducido
Kerrek SB

Deducción se refiere al proceso de determinar el tipo de un parámetro de plantilla a partir de un argumento dado. Se aplica a las plantillas de funciones, auto, y algunos otros casos (por ejemplo, especialización parcial). Por ejemplo, considere:

template <typename T> void f(std::vector<T>);

Ahora si dices f(x)donde declaraste std::vector<int> x;luego T es deducido como inty obtienes la especialización f<int>.

Para que la deducción funcione, el tipo de parámetro de plantilla que se va a deducir tiene que aparecer en un contexto deducible. En este ejemplo, el parámetro de función de f es un contexto tan deducible. Es decir, un argumento en la expresión de la llamada a la función nos permite determinar cuál es el parámetro de la plantilla. T debe ser para que la expresión de llamada sea válida.

Sin embargo, también hay no-Contextos deducidos, donde no es posible la deducción. El ejemplo canónico es “un parámetro de plantilla que aparece a la izquierda de un :::

template <typename> struct Foo;

template <typename T> void g(typename Foo<T>::type);

En esta plantilla de función, el T en la lista de parámetros de la función está en un contexto no deducido. Así no puedes decir g(x) y deducir T. La razón de esto es que no existe una “correspondencia hacia atrás” entre tipos arbitrarios y miembros Foo<T>::type. Por ejemplo, podrías tener especializaciones:

 template <> struct Foo<int>       { using type = double; };
 template <> struct Foo<char>      { using type = double; };
 template <> struct Foo<float>     { using type = bool; };
 template <> struct Foo<long>      { int type = 10; };
 template <> struct Foo<unsigned>  { };

si llamas g(double{}) hay dos respuestas posibles para Ty si llamas g(int{}) no hay respuesta. En general, no existe una relación entre los parámetros de la plantilla de clase y los miembros de la clase, por lo que no puede realizar ninguna deducción de argumentos sensata.


Ocasionalmente, es útil inhibir la deducción de argumentos explícitamente. Este es por ejemplo el caso de std::forward. Otro ejemplo es cuando tienes conversiones de Foo<U> para Foo<T>digamos, u otras conversiones (piense std::string y char const *). Ahora suponga que tiene una función libre:

template <typename T> bool binary_function(Foo<T> lhs, Foo<T> rhs);

si llamas binary_function(t, u), entonces la deducción puede ser ambigua y por lo tanto fallar. Pero es razonable deducir sólo un argumento y no deducir el otro, permitiendo así conversiones implícitas. Ahora se necesita un contexto explícitamente no deducido, por ejemplo como este:

template <typename T>
struct type_identity {
    using type = T;
};

template <typename T>
bool binary_function(Foo<T> lhs, typename type_identity<Foo<T>>::type rhs)
{
    return binary_function(lhs, rhs);
}

(Es posible que haya experimentado tales problemas de deducción con algo como std::min(1U, 2L).)

  • Entonces, está haciendo referencia al segundo caso descrito por el estándar (“Un tipo que es una identificación de plantilla en la que uno o más de los argumentos de plantilla es una expresión que hace referencia a un parámetro de plantilla”), ¿verdad? Si es así, ¿puede hacer un ejemplo del primero (“El especificador de nombre anidado de un tipo que se especificó usando una identificación calificada”)?

    – Zapato

    11 de agosto de 2014 a las 14:32

  • En realidad, ahora que lo leo con atención, creo que es todo lo contrario.

    – Zapato

    11 de agosto de 2014 a las 14:33


  • @Jefffrey: Tal vez algo como template <std::size_t> struct Bar; template <typename T> void(Bar<sizeof(T)>);?

    – KerrekSB

    11 de agosto de 2014 a las 14:36


  • El punto es este: hay una correspondencia uno a uno entre los tipos T y clases de plantilla Foo<T>, por lo que se puede deducir lo primero de lo segundo. Pero hay no correspondencia entre tipos T y miembros arbitrarios Foo<T>::X.

    – KerrekSB

    11 de agosto de 2014 a las 14:38

  • Siento que también podrías responder esto.

    – Baum mit Augen

    11 de agosto de 2014 a las 14:48

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad