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?
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.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 argument0
, so you need to introduce a template function declaration or use the qualified version ofget
asstd::get<0>(ar)
.In standardese
[temp.arg.explicit]/8
: (emphasis mine)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.