¿Qué es un contexto no deducido?

He estado expuesto recientemente a esta pregunta 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 enigmático por decir lo menos.

¿Puede alguien explicar a los simples mortales, como a mí mismo, qué es un contexto no deducido , cuándo ocurre y por qué ocurre?

Es muy simple: la 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 plantillas de funciones, auto y algunos otros casos (por ejemplo, especialización parcial). Por ejemplo, considere:

 template  void f(std::vector); 

Ahora si dices f(x) , donde declaraste std::vector x; , entonces T se deduce como int , y obtienes la especialización f .

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

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

 template  struct Foo; template  void g(typename Foo::type); 

En esta plantilla de función, la T en la lista de parámetros de función está en un contexto no deducido. Por lo tanto, 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::type . Por ejemplo, podrías tener especializaciones:

  template <> struct Foo { using type = double; }; template <> struct Foo { using type = double; }; template <> struct Foo { using type = bool; }; template <> struct Foo { int type = 10; }; template <> struct Foo { }; 

Si llama a g(double{}) hay dos respuestas posibles para T , y si llama a 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 razonable de argumentos.


Ocasionalmente, es útil nhibernate explícitamente la deducción de argumentos. Este es, por ejemplo, el caso de std::forward . Otro ejemplo es cuando tiene conversiones de Foo a Foo , por ejemplo, u otras conversiones (think std::string y char const * ). Ahora supongamos que tienes una función gratuita:

 template  bool binary_function(Foo lhs, Foo rhs); 

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

 template  bool binary_function(Foo lhs, typename std::common_type>::type rhs) { return binary_function(lhs, rhs); } 

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