2012-03-23 13 views
26

Rozważmy następujący program w C++Dlaczego Argument Dependent Lookup nie działa z szablonem funkcji 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)); 
} 

Podczas kompilacji z MSVC 2010, I uzyskać następujący błąd:

error C2065: 'dynamic_pointer_cast' : undeclared identifier 

błąd nie ustępuje jeśli auto zostanie zastąpiony przez std::shared_ptr<A>. Kiedy w pełni kwalifikuję połączenie z std::dynamic_pointer_cast, program pomyślnie się kompiluje.

Również gcc 4.5.1 nie podoba albo:

error: 'dynamic_pointer_cast' was not declared in this scope 

Myślałem, że std::dynamic_pointer_cast zostałby wybrany przez Koenig lookup, od rodzaju x mieszka w przestrzeni nazw std. Czego tu mi brakuje?

+0

Co sprawia, że ​​** std :: dynamic_pointer_cast ** rzuca się? – DumbCoder

+0

@DumbCoder: tak jak mówiłem, program kompiluje się, kiedy używam 'std :: dynamic_pointer_cast'. Po prostu ciekawi mnie, dlaczego kompilator nie wybiera "dynamic_pointer_cast" przez ADL. –

+0

Przepraszam, że przepadła ta część, moja zła !! – DumbCoder

Odpowiedz

24

myślę sekcja §14.8.1/6 (C++ 03, i myślę, że trzyma w C++ 11 również) ma zastosowanie w niniejszej sprawie, który brzmi jak

[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]

Twój przypadek nie wyzwalacza ADL, ponieważ jawnie przekazano argument szablonu i nie ma szablonu o tej samej nazwie dostępnego w witrynie, na której wywoływana jest nazwa dynamic_pointer_cast.

Jeden trick, aby umożliwić ADL jest dodanie obojętne szablon z samym nazwy w kodzie, jak pokazano poniżej:

#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

Idealny. Myślę, że możemy założyć, że to nadal obowiązuje dla C++ 11. Dzięki! –

+0

@AlexandreC .: Wydaje mi się, że także w C++ 11. – Nawaz

+1

Aha! Dobra sztuczka. –

18

Koenig odnośników odnosi się tylko do znalezienia funkcji. W tym przypadku najpierw musisz znaleźć szablon, a następnie utworzyć jego instancję, zanim uzyskasz funkcję. Aby po prostu przeanalizować kod, kompilator musi wiedzieć, że szablon to dynamic_pointer_cast (inaczej "<" jest mniejsze niż, a nie początek listy szablonów); dopóki kompilator nie wie, że dynamic_pointer_cast jest szablonem funkcji, to nawet nie wie, że chodzi o wywołanie funkcji. Wyrażenie, które widzi, to w zasadzie a <b> c, gdzie < i > są operatorami relacyjnymi.

+0

Wygląda na to, że wyszukiwanie Koeniga może również znaleźć szablony funkcji, zob. Odpowiedź Nawaza. Niemniej jednak twój argument jest właściwy. –

+0

Pedantically look, Koenig lookup dotyczy również szablonu funkcji. Po prostu nie działa, gdy jawnie przekazujesz argument szablonu, a nazwa szablonu nie jest widoczna w witrynie połączenia. W tym przypadku nie działa, ponieważ wywołanie nie ma poprawnej składni wywołania funkcji, ponieważ kompilator nie wie, że nazwa jest w rzeczywistości nazwą szablonu funkcji. – Nawaz

+5

@Nawaz W końcu to nie działa, ponieważ standard mówi, że tak nie jest i jest kilka powodów, dla których standard nie mówi, aby działało.Zarówno ten, który dajesz, jak i to, co wyjaśniłem (co wynika z dyskusji w komisji, wiele, wiele lat wstecz), powraca do tego samego podstawowego problemu: aby poprawnie parsować wyrażenie, kompilator musi wiedzieć, że symbol jest szablon, i żeby to wiedzieć, musi to sprawdzić. I nie może użyć wyszukiwania Koeniga, które go szuka, ponieważ nie zostało jeszcze wystarczająco przeanalizowane, by wiedzieć, że jest wywołanie funkcji. –

Powiązane problemy