Search code examples
c++getc++20global-namespace

In C++20, the get<>() function inside <tuple> is no longer in namespace std. Why?


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?


Solution

  • std::get is found by argument-dependent lookup (ADL), because t has a type that is a specialization of the class template std::tuple which is located in the same namespace scope as the std::get overload 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 like swap.

    The reason it fails in C++17 has nothing to do with whether std::get is found, but rather with the rules that determine whether or not the < following get is 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.

    template<typename T>
    void get();
    

    into your global namespace scope, then < will also be assumed to introduce a template argument list because this function template is found for get by 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) and std::get will be found as candidate as well.