On 17 March 2011 18:18, Jonathan Wakely wrote: > On 17 March 2011 18:09, Rodrigo Rivas wrote: >> Hello all. >> >> I've just read the paper titled "Range-based for statements and ADL" >> by Jonathan Wakely and Bjarne Stroustrup at: >> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3257.pdf >> >> The point of this article is that the argument dependent lookup in the >> range-for specification will make some trouble in the real world. E.g: >> #include <vector> >> namespace n >> { >> struct X { void begin(); }; >> struct Y { void begin(); }; >> template<typename T> void begin(T& t) { t.begin(); } >> } >> int main() >> { >> std::vector<n::X> v; >> for (auto i : v) // error: call to begin is ambiguous: std::begin >> or n::begin? >> { >> //... >> } >> } >> >> I've implemented Option 5 from the paper (which is the coolest, IMHO): >> - [...], if _rangeT has a member begin or a member end, begin-expr >> and end-expr are __range.begin() and __range.end(), respectively >> - otherwise, begin-expr and end-expr are begin(__range) and >> end(__range), respectively, where begin and end are looked up with >> argument-dependent lookup [...] >> >> I'm not sure about what should happen if _rangeT has a member begin >> but not a member end. I think that there are just two sensible >> options: >> * Use them only if both members, begin and end, exist. >> * Look for them independently. This is what my patch does. >> >> Also, if the member begin/end is not accessible or not callable, a >> compiler error will follow immediately (this is as expected). >> >> I'll appreciate any comments. > > Hi Rodrigo, > > do you mind if I forward your mail to the committee reflector? The > fact that there's an implementation is useful. > > I think Bjarne's intention is that the lookup is independent and if > one is found but not the other, or if they do not have the right > semantics (i.e. they just happen to be called "begin" and "end" but > are not STL-style range functions returning iterators) then it should > be an error. So I think what you've done is correct. > > Bjarne said: > > Maybe I was being obscure and clearly I should have added a rationale > (thanks), but I actually think that if you try to use a range-for a > class that has "odd" begin and/or end, it should be an error, rather > than "silently" start looking in the enclosing name space. Consider > > struct C { > int* begin(); > // I forgot end() or misspelled end() or gave end the wrong type > }; > > C cont; > // ... > template<class T> T* begin(T); // the nastiest example I could > come up with in a hurry > template<class T> T* end(T); > // ... > for (auto x : cont ) // I'd prefer this to fail >
Actually, re-reading that and the following messages on the thread, I'm wrong about the lookup being independent - if it only finds a begin() member and no end() member it should still try to use r.end(), and therefore give an error. It should not be possible to use r.begin() and end(r)