The following code does not compile in C++17 but from C++20 on:
#include <tuple>
int main() {
auto t = std::make_tuple(1, 2);
get<0>(t); // no std:: required!
return 0;
}
Since this works with both g++ and clang++ and both -stdlib=libc++ and -stdlib=libstdc++ and even in msvc with /std:c++20, I wonder whether this is a "feature". What is the rationale behind this? Is there more pollution to the global namespace besides this?
std::getis found by argument-dependent lookup (ADL), becausethas a type that is a specialization of the class templatestd::tuplewhich is located in the same namespace scope as thestd::getoverload you want to use. This is behavior that has always existed in C++ and is fundamental to making operator overloading work, as well as other customizable function calls likeswap.The reason it fails in C++17 has nothing to do with whether
std::getis found, but rather with the rules that determine whether or not the<followinggetis the less-than operator or the start of an template argument list. Before C++20, if the unqualified name before the<wasn't found at all by usual unqualified (non-ADL) lookup, the program was ill-formed. Since C++20 it is assumed to introduce a template argument list in this situation.For example, if you add a function template named
get, regardless of signature, e.g.into your global namespace scope, then
<will also be assumed to introduce a template argument list because this function template is found forgetby usual unqualified lookup, even in C++17. Then ADL applies to the call as usual (this has always worked this way in every C++ edition) andstd::getwill be found as candidate as well.