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