Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Argument Dependent Lookup doesn't work with function template dynamic_pointer_cast

Consider the following C++ program:

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

When compiling with MSVC 2010, I obtain the following error:

error C2065: 'dynamic_pointer_cast' : undeclared identifier 

The error persists if auto is replaced by std::shared_ptr<A>. When I fully qualify the call with std::dynamic_pointer_cast, the program successfully compiles.

Also, gcc 4.5.1 doesn't like it either:

error: 'dynamic_pointer_cast' was not declared in this scope 

I thought that std::dynamic_pointer_cast would have been picked by Koenig lookup, since the type of x lives in the std namespace. What am I missing here ?

like image 251
Alexandre C. Avatar asked Mar 23 '12 12:03

Alexandre C.


2 Answers

I think section §14.8.1/6 (C++03, and I think it holds in C++11 also) applies to this case which reads as,

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

Your case do not trigger ADL because you explicitly pass template argument and there is no template with the same name available at the site where you call dynamic_pointer_cast.

One trick to enable ADL is to add a dummy template with same name to your code, as shown below:

#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 } 
like image 127
Nawaz Avatar answered Oct 07 '22 12:10

Nawaz


Koenig lookup only applies to finding functions. Here, you first have to find a template, then instantiate it, before you have a function. In order to simply parse the code, the compiler has to know that dynamic_pointer_cast is a template (otherwise, '<' is less than, and not the start of a template argument list); until the compiler knows that dynamic_pointer_cast is a function template, it doesn't even know that a function call is involved. The expression it sees is basically a < b > c, where < and > are the relational operators.

like image 38
James Kanze Avatar answered Oct 07 '22 11:10

James Kanze