Unqualified name lookup for a function-call expression may also consider associated namespaces in order to find the referred function. This feature is called Argument-dependent lookup. The set of associated namespaces that are being searched through include the namespaces of the types of the function call arguments themselves, as well as the namespaces of template arguments of the class template types of the function call arguments. In other words, for a function call:
foo(A::B<C::D>{});
the set of associated namespaces include namespace A
and namespace C
, and both are examined to find the declaration of function foo
.
In the first case:
random_shuffle(intVec.begin(), intVec.end());
std::random_shuffle
is found via ADL which was triggered only because in the VC++ Standard Library implementation std::vector<int>::iterator
is a class type defined within the std
namespace (std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>
), hence std
was an associated namespace to perform a name lookup. This, however, is not guaranteed to work, since a vector iterator could also be a pointer, or live outside of namespace std
.
In the second case:
std::random_shuffle<vector<int>::iterator>(intVec.begin(), intVec.end());
the compiler performs a qualified name lookup.
In the third case:
random_shuffle<vector<int>::iterator>(intVec.begin(), intVec.end());
the following bullet applies:
[temp.arg.explicit]/p8:
8 (...) 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.
In other words, f(a)
can trigger ADL, but f<B>(a)
-- providing template arguments explicitly to a function call, which is precisely your case -- can not.
This bullet seems to be valid only until C++20.