2012-07-23 13 views
8

Tengo una clase de plantilla NB::B<T> derivada de una clase que no es de plantilla NA::A en un espacio de nombres. act<T> es una función de plantilla que llama a la función add_ref en una instancia de su argumento de plantilla. Específicamente, act<NB::B<int>> quiere encontrar add_ref definido en el espacio de nombres de la base NB::B usando ADL. El ejemplo completo es el siguiente:Búsqueda dependiente del argumento a través de la base de una clase de plantilla

template<class T> 
void act() { 
    T* p = 0; 
    add_ref(p); // the failing line 
} 

namespace NA 
{ 
    struct A { }; 

    // I want ADL to find this: 
    void add_ref(A* p) { 
    } 
} 

namespace NB 
{ 
    // template class with non-template base 
    template <class T> 
    struct B: NA::A { }; 

    typedef B<int> Bi; 

    // using NA::add_ref; // fixes the problem 
} 

int main() 
{ 
    act<NB::Bi>(); 
} 

Esto compila bien en gcc (4.7.0). Y en Comeau en línea. Sin embargo clang (3.1) falla:

a.cpp:4:3: error: use of undeclared identifier 'add_ref' 

Al mismo tiempo, la norma dice:

3.4.2/2 ...

- Si T es una plantilla-id, sus asociados espacios de nombres y clases son el espacio de nombres en el que se define la plantilla; para plantillas de miembros, la clase de plantilla de miembro; los espacios de nombres y las clases asociados con los tipos de argumentos de plantilla proporcionados para los parámetros de tipo de plantilla (sin incluir los parámetros de plantilla de plantilla); los espacios de nombres en los que se definen los argumentos de plantilla de plantilla; y las clases en las que se definieron las plantillas de miembros utilizadas como argumentos de plantilla de plantilla.

Sorprendentemente, las bases de la plantilla no se enumeran como rutas a los espacios de nombres asociados. Por lo tanto, el comportamiento de clang parece ser correcto. Y Comeau y gcc aceptan un programa incorrecto.

Al mismo tiempo, 3.4.2/3 establece que using 's en espacios de nombres de argumentos no tienen ningún efecto:

Al considerar un espacio de nombres asociado, la búsqueda es la misma que la búsqueda se realiza cuando el espacio de nombres asociado se utiliza como un calificador (3.4.3.2) excepto que:

- Se ignoran todas las directivas using en el espacio de nombres asociado.

Pero cuando descomiento la línea using NA::add_refclang está contento de compilar la prueba.

para poner mi ejemplo en perspectiva práctica, se puede pensar que act era un método de boost::intrusive_ptr, add_ref(A*) fue intrusive_ptr_add_ref(CBase*) y B fue alguna plantilla, que se deriva de la base CBase.

En este sentido tengo varias preguntas:

  1. Estoy en lo cierto que clang 's es correcto rechazar mi programa de pruebas, y gcc y Comeau no siguen el estándar?

  2. ¿Hay alguna razón por la cual el estándar especifique un comportamiento poco práctico (no permite usar bases de clase de plantilla como espacios de nombres asociados)?

  3. ¿Está clang mal aceptando mi programa de prueba con la directiva using NA::add_ref en el terreno de 3.4.2/3?

  4. ¿Debo informar un error? :)

P.S. He leído clang Language Compatibility FAQ y no he encontrado una respuesta allí.

+0

¿Ayuda el modo C++ 11? C++ 11 parece haber aclarado la redacción, ya que de hecho 'NB :: B ' es una clase (que es una especialización de plantilla), no una plantilla. (Las reglas, IIUC, son que los espacios de nombres asociados con la plantilla cuyo tipo es una especialización * se agregan * a los espacios de nombres asociados a la clase.) –

+0

¿No será esto muy frágil? En algún momento, probablemente agregue una implementación predeterminada de 'add_ref' que siempre será una mejor coincidencia que el espacio de nombres asociado de la base directa. – pmr

+0

@LucDanton, tienes razón. Ambos puntos (sobre los espacios de nombres asociados de 'class' y' template-id') se aplican a la clase 'template-id''s. –

Respuesta

6

De n3337, que es básicamente C++ 11 con pequeños cambios de redacción, la 3.4.2/2 lee:

Para cada tipo de argumento T en la función de llamada [...] Los conjuntos de espacios de nombres y las clases se determinan de la siguiente manera: [...]

  • Si T es un tipo de clase (incluidos los sindicatos), sus clases asociadas son: la clase misma; la clase de la que es miembro, si la hay; y sus clases de base directa e indirecta. Sus espacios de nombres asociados son los espacios de nombres de los cuales sus clases asociadas son miembros. Además , si T es una especialización de plantilla de clase, ...

Y luego continúa con básicamente la misma cotización que usted ha escrito en la pregunta. La diferencia importante aquí es además, lo que significa que la lista que citó (y omití) es además de los espacios de nombres ya mencionados, y eso incluye los espacios de nombres de los cuales la clase base es miembro.

  1. Gcc y comeau tienen razón, y clang ++ se equivoca al rechazar el código.

  2. < no se aplica>

  3. Clang ++ está mal en rechazarla sin la using NA::add_ref.

  4. Sí, probablemente deba informar un error. Parece que ya se ha informado y solucionado.

+1

El error ya fue informado hace un tiempo y corregido. zhr bug was thag clang no inatantiate la plantilla para encontrar sus clases base (y sus declaraciones de amigos) –

+0

Gracias, @ david-rodriguez-dribeas. Eso "además" aclara el problema. –

+0

@ johannes-schaub-litb, ¿hay alguna posibilidad de que recuerde un enlace al error del que está hablando? Acabo de comprobar esto en una compilación nueva del tronco 'clang' y el error todavía está presente. –

Cuestiones relacionadas