The following code fails as expected, because no overload of get
is found. Using std::get
would solve the problem.
#include <array>
int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//fails, get was not declared in this scope
}
However, introducing a templated version of get
, even though it's not matching the function call, somehow makes the compiler use the std::get
version:
#include <array>
template <typename T>
void get(){};
int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//returns 2
}
I can't find any part of the standard that explains this. Is this a bug in all 3 compilers I tested (probably not), or am I missing something?
This behaviour was tested in
- MSVC 15.9.2
- Clang 8.0.0
- GCC 9.0.0 (still an experimental version)
EDIT:
I am aware of ADL. But if ADL makes the second code work, why does it not in the first part?
ADL is not used when explicit template arguments are involved unless you introduce a template function declaration at the call point. You're using an unqualified form of get
using a non-type template argument 0
, so you need to introduce a template function declaration or use the qualified version of get
as std::get<0>(ar)
.
In standardese [temp.arg.explicit]/8
: (emphasis mine)
[ Note: For simple function names, argument dependent lookup (6.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 (6.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.
EDIT:
As @Yakk - Adam Nevraumont has pointed out in the comment, without the presence of the template function declaration, the expression get<0>(ar)
will be parsed as (get<0)>(ar)
, i.e as a serie of comparison expressions instead of a function call.
Note that this changed in C++20 as a result of P0846R0. An unqualified name followed by a <
token for which ordinary unqualified lookup either finds one or more functions or finds nothing is now assumed to name a template and the <
is parsed accordingly.