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

社会主义新天地 提交于 2019-12-04 09:56:59

问题


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 ?


回答1:


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
}



回答2:


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.



来源:https://stackoverflow.com/questions/9838862/why-argument-dependent-lookup-doesnt-work-with-function-template-dynamic-pointe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!