On 2015-02-19 14:36, Thiago Macieira wrote: > On Thursday 19 February 2015 12:07:04 Matthew Woehlke wrote: >> On 2015-02-19 07:29, Daniel Teske wrote: >>> Qt's container classes and C++11 range based for loop do not mix very >>> well. >>> Ranged based for uses std::begin(container), which if not overloaded calls >>> container.begin(), which detaches. >> >> As an aside, the "correct" fix for this IMHO is for range-based for to >> support a mechanism for marking the RHS 'const', whether or not it >> otherwise would be so. >> >> Worst case, Qt could (should?) implement something like: >> >> struct QConstWrapper<ContainerType> >> { >> ContainerType::const_iterator begin() const; >> ContainerType::const_iterator end() const; >> // remaining "magic" elided >> }; >> >> QConstWrapper<ContainerType> qConst(ContainerType const&); >> >> That said, note that range-based for also differs from foreach in that >> the former operates on the original container, whereas the latter >> operates on a copy. > > It actually needs to be: > > template <typename T> const T qConst(const T &t) { return t; } > > It needs to create a copy and return it. There's a gotcha with range-based > for > that it is defined in such a way that your temporaries may be destroyed > before > the iteration. The standard defines it as: > > { > auto && __range = <your range>; > for ( auto __begin = std::begin(__range), > __end = std::end(__range); > __begin != __end; > ++__begin ) { > <for-range-declaration> = *__begin; > <statement> > } > } > > If you have a temporary in your right hand of the ':' it will get lifetime- > extended by that __range reference. Any other temporaries will get destroyed. > > That means a cast works and a copy works. Returning a reference doesn't.
You'll note that I did *not* return a reference. Returning a copy may be okay for Qt since containers are COW (in fact, your version would result in a range-based for that works much more like Q_FOREACH, which is probably good for some cases). What I was aiming for was rather a class that internally holds a reference to the container (such class would be copyable) and forwards the calls to begin/end to that container, such that in a range-based for it appears to *be* the container, but forces use of const_iterator. Note that this would work equally well for non-Qt containers, as long as they have 'IteratorType {begin,end}() const' methods. (Trailing return specification may be required to permit the container's iterator type to be unknown.) I was initially thinking that this was perhaps simple enough to not be worth it. Given your point, I am leaning more toward that it *would* be valuable. (I still think the best solution is for C++ to just accept 'const <expr>' as a modifier to make the type of '<expr>' constant, regardless of whether or not it was. This would allow things like 'for (auto item : const container)', '(const this)->begin()', 'foo(const bar)', and so forth.) -- Matthew _______________________________________________ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development