2011-09-10 9 views
22

Considere este ejemplo he encontrado en el sitio web de IBM:GCC, Clang e IBM no están de acuerdo en cómo realizar la búsqueda de nombre dependiente del parámetro de plantilla. ¿Cuál es la correcta?

#include <iostream> 
using namespace std; 

void f(double) { cout << "Function f(double)" << endl; } 

template<class T> void g(T a) { 
    f(123); 
    h(a); 
} 

void f(int) { cout << "Function f(int)" << endl; } 
void h(double) { cout << "Function h(double)" << endl; } 

void i() { 
    extern void h(int); 
    g<int>(234); 
} 

void h(int) { cout << "Function h(int)" << endl; } 

int main(void) { 
    i(); 
} 

¿Qué va a imprimir?

  • La documentación de IBM Adapté este ejemplo de, disponible here, dice que va a imprimir:

    Function f(double) 
    Function h(double) 
    

    La razón de esto es que el nombre de plantilla de parámetros dependientes de las operaciones de búsqueda se lleva a cabo justo antes de la creación de instancias de i(), por lo que encuentra h(double) pero no h(int).

  • Cuando compilo usando GCC 4.4.1, imprime:

    Function f(double) 
    Function h(int) 
    

    GCC parece estar mirando hacia arriba los nombres de los parámetros de plantilla-dependiente en la plantilla después de todo lo demás ha sido compilado, por lo que encuentra ambos h(double) y h(int), y prefiere este último.

  • Cuando lo compilo con Clang 2.8, no se puede compilar. El error del compilador es:

    ibm_example.cc:8:3: error: use of undeclared identifier 'h' 
        h(a); 
    ^
    ibm_example.cc:16:3: note: in instantiation of function template specialization 'g<int>' requested here 
        g<int>(234); 
    ^
    1 error generated. 
    

    Clang parece estar mirando hacia arriba los nombres de los parámetros de plantilla-dependiente en la plantilla en el punto donde se declara la plantilla, por lo que no se encuentra ni h(double)h(int).

¿Cuál es la correcta?

+0

posible duplicado de [? ¿Cuáles son las reglas para la elección de las funciones de plantilla sobrecargados] (http://stackoverflow.com/questions/1177739/what-are -the-rules-for-choosing-from-overloaded-template-functions) –

+0

Sin cambios para GCC 4.5.1 FWIW. – ergosys

+1

@Foo: Definitivamente no es un duplicado de esa pregunta, se trata de la resolución de sobrecarga, esta es sobre el alcance y qué símbolos son visibles en el momento de la definición. – ildjarn

Respuesta

13

Todos son correctos. No, en serio, sigue leyendo ...

template<class T> void g(T a) { 
    f(123); 
    h(a); 
} 

Aquí, f es un nombre no dependiente pero h es un nombre dependiente de acuerdo con 14.6.2/1. f se busca

nombres no dependientes utilizados en una definición de plantilla se encuentran utilizando la búsqueda de nombre usual y encuadernado en el punto que se utilizan.

f se busca inmediatamente y unido a void f(double), la única f visible en ese punto.

De acuerdo con 14.6.4.1, el punto de instanciación de void g<int>(int) es inmediatamente posterior a la definición de void i(), donde se utiliza.

[..] De lo contrario, el punto de instanciación de una especialización tales sigue inmediatamente a la declaración de espacio de nombres alcance o definición que se refiere a la especialización.

Esto significa que las fuentes para resolver el nombre dependiente son declaraciones visibles en la definición de template<class T> void g(T a) y "declaraciones de espacios de nombres asociados con los tipos de los argumentos de la función tanto desde el contexto de instanciación (14.6.4.1) y de la definición contexto "(14.6.4).

Sin embargo, como int es un tipo fundemantal, el conjunto de espacios de nombres asociados está vacío (3.4.2) (no, ni siquiera se incluye el espacio de nombres global) y de acuerdo con 14.6.4.2 solo busca utilizando los espacios de nombres asociados que puede usar el contexto de instanciación de plantilla, la búsqueda de nombre normal no calificada solo puede usar lo que está visible en el contexto de definición de plantilla. Esto confirma lo que se dijo en 14.6.4.

Ahora, el punto extra. 14.6.4.2 pasa a decir:

Si se enferma-formó la llamada o podría encontrar un mejor partido tuvo las operaciones de búsqueda dentro de los espacios de nombres asociados consideradas todas las declaraciones de funciones con enlace externo introducido en dichos espacios de nombres en toda traducción unidades, no solo teniendo en cuenta las declaraciones que se encuentran en la definición de la plantilla y los contextos de creación de instancias de la plantilla, entonces el programa tiene un comportamiento indefinido.

La llamada es mal formada debido búsqueda falla (la parte sobre los espacios de nombres asociados no se aplica aquí), por lo que el comportamiento es indefinido explícitamente así que cualquier cosa podría suceder. Por lo tanto, ninguno de los comportamientos vistos muestra una no conformidad con el estándar aunque, para mí, el diagnóstico de Clang parece estar más en consonancia con el estándar.

(Todas las referencias ISO/IEC 14882: 2011).

+0

Se puede interpretar la parte sobre comportamiento indefinido con un enlace diferente, que parece tener más sentido para mí: "Si {{la llamada estuviera mal formada} o {encontraría una coincidencia mejor}, la búsqueda dentro de los espacios de nombres asociados se considera todas las declaraciones de funciones con enlaces externos introducidos en esos espacios de nombres en todas las unidades de traducción}, ... entonces el programa tiene un comportamiento indefinido ". –

+0

O redactado de forma diferente (parte posterior del párrafo "Si {{la llamada estaría mal formada} o {encontraría una mejor coincidencia} tenía la búsqueda dentro de los espacios de nombres asociados no solo consideradas las declaraciones encontradas en la definición de la plantilla y contextos de instanciación de la plantilla }, entonces el programa tiene un comportamiento indefinido. " –

+0

Este enlace tiene más sentido para mí porque el compilador (a diferencia del vinculador) no puede ver múltiples unidades de traducción, por lo que el estándar no requiere un diagnóstico para aquellos casos en que la implementación lo haría, la llamada sería ambigua/mal formada o encontraría una mejor coincidencia. –

Cuestiones relacionadas