2011-04-18 11 views
8

¿Por qué no se compila con GCC 4.4?Plantillas de función de sobrecarga en espacios de nombres

template<typename T> 
class A { 
public: 
    void foo() { 

    } 

private: 
    T x; 
}; 

namespace Ns { 
template<typename T> 
void do_it (A<T> a) { 
    a.foo(); 
} 
}; 

template<typename T> 
void myfun (T x) { 
    Ns::do_it (x); 
} 

template<typename T> 
class B { 
public: 
    void bar() { 

    } 

private: 
    T x; 
}; 

namespace Ns { 
template<typename T> 
void do_it (B<T> b) { 
    b.bar(); 
} 
}; 

int main() { 
    A<int> a; 
    B<int> b; 

    myfun (a); 
    myfun (b); // error: no matching function call to do_it(B<int>&) 

    return 0; 
} 

Debe tener algo que ver con el espacio de nombres de do_it. Cuando elimino el espacio de nombres alrededor, se compila.

Antecedentes: Estoy creando un conjunto de funciones que pueden usarse con muchas clases de contenedores diferentes. Para manejar las diferentes interfaces de manera uniforme, utilizo funciones independientes que están sobrecargadas para cada una de las clases de contenedor. Estas funciones se colocarán en un espacio de nombres para evitar saturar el espacio de nombres global con ellas.

Se piensa que las definiciones para B provienen de un archivo de cabecera diferente al de A, por lo que el reordenamiento no es una opción.

+0

¡Es un error tipográfico! El HTML tragó el . –

+0

VS 2010 compila el código anterior, y creo que es correcto al hacerlo, pero este es un ejemplo complicado. ¡Buena pregunta! –

+0

Lo mismo con VS2008, acabo de comprobarlo. ¿Podría ser esto un error en GCC o su interpretación es diferente de la de Microsoft? El hecho de que funcione sin un espacio de nombres indicaría que es un error, ¿no? –

Respuesta

6

La razón es que solo se realiza ADL en el momento de la llamada. Otras búsquedas de funciones solo se realizan en la definición de la plantilla de función myfun.

Y en ese contexto de definición, solo se declara la sobrecarga do_it que acepta el A<int>.

Editar: Si desea tener una referencia estándar para esto, consulte [temp.dep.candidate] y [temp.res] p1.

+0

¿Hay una manera estándar de resolver esto usando espacios de nombres? –

+2

@Mark si desea tener las funciones en el espacio de nombres 'Ns' consideradas, puede derivar' B 'de una clase ficticia definida en ese espacio de nombres, de modo que ADL busque en el espacio de nombres' Ns'. O puede pasar argumentos de plantilla a 'B ' que asocian la especialización generada con 'Ns'. Por ejemplo 'B >' (ADLAssociator podría ser una plantilla de clase pequeña que solo almacena 'T t;'). O pasa esas clases asociativas como argumentos ficticios adicionales: 'B '. Hay muchas opciones para este. Lo más limpio parece ser derivar 'B' de una clase o definirla en' NS'. –

+5

¿Qué hay de cambiar la función gratuita en un miembro de clase estática: 'namespace Ns {plantilla struct dispatch; } '(declararlo por adelantado), luego para cada tipo nuevo, agregue una especialización:' namespace Ns {plantilla struct dispatch < B> {static void do_it (B x) {x.bar()}}; } ', y tienen' template void myfunc (T t) {Ns :: dispatch :: do_it (t); } ' –

Cuestiones relacionadas