2012-03-23 12 views
26

Consideremos el siguiente programa en C++:Por qué argumento de búsqueda Dependiente no funciona con plantilla de función dynamic_pointer_cast

#include <memory> 

struct A {}; 

struct B : A {}; 

int main() 
{ 
    auto x = std::make_shared<A>(); 
    if (auto p = dynamic_pointer_cast<B>(x)); 
} 

Al compilar con MSVC 2010, me obtener el siguiente error:

error C2065: 'dynamic_pointer_cast' : undeclared identifier 

el error persiste si auto se reemplaza por std::shared_ptr<A>. Cuando califico completamente la llamada con std::dynamic_pointer_cast, el programa se compila con éxito.

Además, gcc 4.5.1 no le gusta, sea:

error: 'dynamic_pointer_cast' was not declared in this scope 

pensé que std::dynamic_pointer_cast habría sido escogido por Koenig lookup, ya que el tipo de x vidas en el espacio de nombres std. Que me estoy perdiendo aqui ?

+0

¿Qué significa hacer que ** std :: dynamic_pointer_cast ** aparezca? – DumbCoder

+0

@DumbCoder: como dije, el programa se compila cuando uso 'std :: dynamic_pointer_cast'. Solo tengo curiosidad sobre por qué el compilador no selecciona 'dynamic_pointer_cast' por ADL. –

+0

Lo siento, ha robado esa parte, mi mal !! – DumbCoder

Respuesta

24

Creo sección §14.8.1/6 (03 C++, y creo que tiene en C++ 11 también) se aplica a este caso que dice lo,

[Note: For simple function names, argument dependent lookup (3.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (3.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.

[Example:

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 
} 

—end example] —end note]

Su caso no lo hacen desencadenar ADL porque expira explícitamente el argumento de plantilla y no hay ninguna plantilla con el mismo nombre disponible en el sitio donde llama al dynamic_pointer_cast.

Un truco para permitir ADL es añadir una plantilla de maniquí con mismo nombre a su código, como se muestra a continuación:

#include <memory> 

struct A {}; 

struct B : A {}; 

template<int> //template parameter could be anything! 
void dynamic_pointer_cast(); //ADD this. NO NEED TO DEFINE IT 

int main() 
{ 
    auto x = std::make_shared<A>(); 
    if (auto p = dynamic_pointer_cast<B>(x)); //now it should work through ADL 
} 
+1

Perfecto. Creo que podemos suponer que esto sigue siendo válido para C++ 11. ¡Gracias! –

+0

@AlexandreC .: Creo que también es válido en C++ 11. – Nawaz

+1

Aha! Buen truco también. –

18

búsqueda Koenig sólo se aplica a la búsqueda de funciones. Aquí, primero tiene que encontrar una plantilla, luego crear una instancia, antes de tener una función. Para simplemente analizar el código, el compilador debe saber que dynamic_pointer_cast es una plantilla (de lo contrario, '<' es menor que, y no es el comienzo de una lista de argumentos de la plantilla); hasta que el compilador sepa que dynamic_pointer_cast es una plantilla de función, ni siquiera sabe que se trata de una llamada a función. La expresión que ve es básicamente a <b> c, donde < y > son los operadores relacionales.

+0

Parece que la búsqueda de Koenig también puede encontrar plantillas de funciones, cf. La respuesta de Nawaz. No obstante, tu argumento es el correcto. –

+0

Pedadicamente hablando, la búsqueda de Koenig también se aplica a la plantilla de función. Simplemente no funciona cuando expira explícitamente el argumento de la plantilla y el nombre de la plantilla no está visible en el sitio de la llamada. En este caso, no funciona porque la llamada no tiene una sintaxis de llamada a función correcta, ya que el compilador no sabe que el nombre es en realidad un nombre de plantilla de función. – Nawaz

+5

@Nawaz Al final, no funciona porque el estándar dice que no, y hay varias razones por las cuales el estándar no dice que funcione.Tanto el que das como el que explico (que proviene de discusiones en el comité, muchos, muchos años atrás) vuelven al mismo problema básico: para analizar correctamente la expresión, el compilador debe saber que el símbolo es un plantilla, y para saber eso, tiene que buscarlo. Y no puede usar la búsqueda de Koenig buscándolo, porque aún no ha analizado lo suficiente como para saber que hay una llamada de función. –

Cuestiones relacionadas