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_ref
clang
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:
Estoy en lo cierto que
clang
's es correcto rechazar mi programa de pruebas, ygcc
yComeau
no siguen el estándar?¿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)?
¿Está
clang
mal aceptando mi programa de prueba con la directivausing NA::add_ref
en el terreno de3.4.2/3
?¿Debo informar un error? :)
P.S. He leído clang Language Compatibility FAQ y no he encontrado una respuesta allí.
¿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.) –
¿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
@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. –