Why is argument-dependent lookup (ADL) choosing class method instead of more fiting free function?

342 views Asked by At

According to cppreference, in Argument-dependent lookups

function names are looked up in the namespaces of their arguments in addition to the scopes and namespaces considered by the usual unqualified name lookup.

However, why is it then that in the following example in function A::member_function() the class-method begin() is choosen which 1) takes 0 arguments and 2) isn't even in the namespace of std::vector, the argument of the function? Shouldn't ADL go to the namespace of the arguments (which is std for vector) and choose the free function std::begin()?

#include <unordered_map>
#include <vector>


class A
{
public:
    using value_t = std::unordered_map<int, char>;
public:
    void member_function();
    value_t::iterator begin() { return map_.begin(); }

private:
    value_t map_;
};


void A::member_function() 
{
    std::vector<int> hello;
    auto it = begin(hello);
}

I'm also happy for a workaround if this is really the way ADL works.

1

There are 1 answers

2
user17732522 On

ADL is not done if ordinary unqualified name lookup finds a class member.

You can avoid this issue with a using-declaration, so that unqualified name lookup is guaranteed to always result in std::begin:

using std::begin;
auto it = begin(hello);

This will always find std::begin, but also do ADL to find other begin overloads.

You can also use a qualified call std::begin(hello); which will forward correctly to the .begin member of the argument, if possible, but will not do any ADL.

In C++20 there is std::ranges::begin, which can be used instead of the method above. It is a customization point object and will forward to the correct begin for the argument more generally, either to a member if possible or via ADL.