2010-06-01 10 views
70

¿Qué parte de la especificación de C++ restringe la búsqueda dependiente de argumentos para que no encuentre plantillas de funciones en el conjunto de espacios de nombres asociados? En otras palabras, ¿por qué la última llamada en main a continuación no se puede compilar?¿Por qué ADL no encuentra plantillas de funciones?

namespace ns { 
    struct foo {}; 
    template<int i> void frob(foo const&) {} 
    void non_template(foo const&) {} 
} 

int main() { 
    ns::foo f; 
    non_template(f); // This is fine. 
    frob<0>(f); // This is not. 
} 
+0

¿Quiere decir, que se espera para trabajar FROB() sin escribir ns :: FROB()? – Simon

+0

Sí, en la forma de una función sin plantilla. – Hugh

+0

FYI el código anterior también falla en Comeau: http://www.comeaucomputing.com/tryitout/ - agregando 'using namespace ns;' o 'ns ::' calificación pasa compilación. Esta es una buena pregunta. – fbrereto

Respuesta

74

Esta parte explica que:

C++ estándar 03 14.8.1.6:

[Nota: Para obtener los nombres de funciones simples, dependiente de búsqueda argumento (3.4.2) se aplica incluso cuando el nombre de la función no es visible dentro del alcance de la llamada. Esto se debe a que la llamada todavía tiene la forma sintáctica de una llamada de función (3.4.1). Pero cuando se utiliza una plantilla de función con argumentos de plantilla explícitos, la llamada no tiene la forma sintáctica correcta a menos que haya una plantilla de función con ese nombre visible en el punto de la llamada. Si no se muestra dicho nombre, la llamada no está sintácticamente bien formada y no se aplica la búsqueda dependiente de los argumentos. Si algún nombre es visible, se aplica la búsqueda dependiente del argumento y se pueden encontrar plantillas de funciones adicionales en otros espacios de nombres.

namespace A { 
    struct B { }; 
    template<int X> void f(B); 
} 
namespace C { 
    template<class T> void f(T t); 
} 
void g(A::B b) { 
    f<3>(b); //ill-formed: not a function call 
    A::f<3>(b); //well-formed 
    C::f<3>(b); //ill-formed; argument dependent lookup 
       // applies only to unqualified names 
    using C::f; 
    f<3>(b); //well-formed because C::f is visible; then 
       // A::f is found by argument dependent lookup 
} 
+4

+1 Buena respuesta. – fbrereto

+0

Excelente, gracias. – Hugh

+0

Ah, no pude encontrar esa referencia :) +1 –

0

Editar: No, esto no está bien. Ver @Kornel's answer.


No estoy del todo seguro, pero después de haber consultado BS de "El lenguaje de programación C++" Creo que la sección Apéndice C 13.8.4 podría ser la causa.

Dado que frob es una plantilla, uno podría posiblemente especializarse para i=0 en un punto después de llamarlo. Esto significa que la implementación se quedaría con dos formas posibles de elegir qué frob llamar, ya que parece que puede elegirlo en el momento de la instanciación o al final del procesamiento de la unidad de traducción.

Por lo tanto, creo que el problema es que podría hacer

namespace ns { 
    struct foo {}; 
    template<int i> void frob(foo const&) {} 
} 

int main() { 
    ns::foo f; 
    frob<0>(f); 
    return 0; 
} 

namespace ns { 
    template<> void frob<0>(foo const&) { /* Do something different*/ } 
} 
+0

No, toma los espacios de nombres y todavía tienes tu problema, ¿verdad? La especialización después del uso es un problema normal en C++, la forma especializada no se usa si se declara después. –

+0

@ Kornel: Ah sí, eso da un error diferente, uno más en línea con lo que describí. Muy bien, gracias por señalar eso. – Troubadour

3

me gustaría perfeccionar respuesta ligeramente aceptado. No está claro en la pregunta OP, pero la parte importante de la norma (citado por Kornel) es la siguiente (el énfasis es mío):

Pero cuando se utiliza una plantilla de función con argumentos de plantilla explícitas, la llamada no tiene la forma sintáctica correcta

así que lo que está prohibido es confiar en ADL y usar argumentos de plantilla explícitos. Desafortunadamente, el uso de argumentos de plantilla sin tipo requiere el uso de argumentos explícitos (a menos que tengan valores predeterminados).

A continuación se muestra el código de ejemplo mostrando este .:

[live]

#include <string> 
#include <utility> 

namespace C { 
    struct B { }; 
    template<class T> void f(T t){} 
} 

void g(C::B b) { 
    f(b);   // OK 
    //f<C::B>(b); // ill-formed: not a function call, but only 
        // because explicit template argument were used 

    std::string s; 
    move(s);      // OK 
    //move<std::string&>(s);  // Error, again because 
           // explicit template argument were used 
    std::move<std::string&>(s); // Ok 
} 

int main() 
{ 
C::B b; 
g(b); 
} 
Cuestiones relacionadas