¿Qué compilador es correcto para el siguiente comportamiento de sobrecarga / especialización?

StackOverflow https://stackoverflow.com/questions/403929

Pregunta

Considere el siguiente código:

#include <stdio.h>

namespace Foo {
  template <typename T>
  void foo(T *, int) { puts("T"); }

  template <typename T>
  struct foo_fun {
    static void fun() { foo((T *)0, 0); };
  };
}

namespace Foo {
  void foo(int *, int) { puts("int"); }
}

using namespace Foo;

int main() {
  foo_fun<int> fun;
  fun.fun();
}

¿Cuál es la salida esperada? " T " o int?

Un compilador (gcc 4.0.1 del Xcode 3.1.2 de Apple) emite "int", otros dos compiladores (gcc 4.1.2 y 4.1.3) emite "T".

Si muevo la declaración / definición de foo (int *, int) antes de la versión de foo (T *, int), toda la salida " int " ;. ¿El orden de sobrecarga / especialización en este caso está definido por la norma actual?

¿Fue útil?

Solución

El segundo void foo (... es una sobrecarga (y no una especialización) que no es visible en la definición de foo_fun :: fun , por lo que no se vería ' t se encuentra en el contexto de la definición de la plantilla. Debido a que T * es un tipo dependiente, la resolución de foo en la expresión foo ((T *) 0, 0) se retrasará hasta que se considere el tiempo de creación de instancias de la plantilla y el contexto de la creación de instancias. Sin embargo, 14.6.4.2 de la norma dice que si el nombre de la función es no calificado-id pero no se considera un template-id , por lo que para la búsqueda no ADL solo se consideran las funciones visibles en el punto de definición de la plantilla. No hay argumentos de función desde el espacio de nombres Foo , por lo que no se realiza una búsqueda dependiente del argumento, por lo tanto, se llama a la versión de plantilla de foo y no a la sobrecarga que no es de plantilla.

Muchas gracias a litb por las correcciones a esta respuesta.

Si lo convirtió en una especialización como se muestra a continuación, luego, cuando se eligen las especializaciones en el momento de creación de instancias de la plantilla, se puede llamar a la especialización siempre que la especialización relevante sea visible en el punto en el que se crea una instancia de la plantilla de función para int .

namespace Foo {
    template<>
    void foo<int>(int *, int) { puts("int"); }
}

Capítulo 14 de la norma actual, pero no es muy legible :)

Editar: Si tuviera que elegir la parte más relevante de la norma, probablemente sería 14.6 [temp.res] para 9. (Un poco abreviado) Si un nombre no depende de un parámetro de plantilla , una declaración para ese nombre debe estar dentro del alcance en el punto donde aparece el nombre en la definición de la plantilla; el nombre está vinculado a la declaración encontrada en ese punto y este enlace no se ve afectado por las declaraciones que son visibles en el momento de la instanciación.

Editar, editar: Pero también debes tener en cuenta 14.6.4.2 [temp.dep.candidate]. Es muy difícil y peligroso tratar de hacer referencia al estándar debido a todas las interdependencias, esta respuesta es un ejemplo de ello.

Otros consejos

Como regla general, de las dos versiones de un compilador, es probable que la última sea más estándar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top