问题
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