struct S
{
vector<int> v;
void method()
{
begin(v);
}
};
The above code snippet compiles fine, because of ADL until I add
auto begin() { return begin(v); }
to the class declaration. At that point C++ forgets about ADL and instead prefers S::begin
that doesn't even have a viable overload, producing the error
error: no matching function for call to ‘S::begin(std::vector<int>&)’ begin(v);
Is there any fix to this? I am asking, because after reading Why use non-member begin and end functions in C++11?, I started using begin()
and end()
free functions everywhere for consistency, but now I am getting conflicts after defining my own begin()
and end()
methods.
You're using begin
as an unqualified name, and unqualified name lookup
... examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.
From your member function's perspective, the first scope providing a name begin
is the class scope, so it populates the overload set from that scope, and stops looking.
Only after this name lookup stage, does it try to choose one of the overload set, and decide nothing matches. The compiler doesn't then go back and start searching from the next scope, it just gives up.
Your options are:
use the existing container member function instead of the free function (this is slightly less verbose than the explicitly-qualified version below)
auto begin() { return v.begin(); }
use qualified names instead
auto begin() { return ::std::begin(v); }
add the correct overload to class scope, with using std::begin;
Ignore that one, I forgot you can't introduce non-member names at class scope with using
.
inject the correct overload into the narrower scope of the member function body itself, so the search stops there
auto begin() { using std::begin; return begin(v); }
stop providing a begin
member function in the first place, and instead add a non-member begin
overload to the enclosing namespace. This is more modern and avoids the lookup problem.
namespace N {
struct S { std::vector<int> v; };
std::vector<int>::iterator begin(S& s) { return s.v.begin(); }
// and end, cbegin, etc. etc.
}