3

I tried to overload (c)begin/(c)end functions for a class so as to be able to call C++11 range-based for loop.

It works in most of the cases, but I don't manage to understand and solve one :

for (auto const& point : fProjectData->getPoints()){ ... }

This line returns error:

Error C2662: 'MyCollection<T>::begin' : cannot convert 'this' pointer from 'const MyCollection' to 'MyCollection<T> &'

because fProjectData is a pointer to const. If I make it non-const, it does work. I don't understand why, considering that cbegin() & cend() are developped with exactness as begin() & end() functions.

Here are my functions developped (in the header file) in MyCollection:

/// \returns the begin iterator
typename std::list<T>::iterator begin() {
    return objects.begin();
}

/// \returns the begin const iterator
typename std::list<T>::const_iterator cbegin() const {
    return objects.cbegin();
}

/// \returns the end iterator
typename std::list<T>::iterator end() {
    return objects.end();
}

/// \returns the end const iterator
typename std::list<T>::const_iterator cend() const {
    return objects.cend();
}

Any ideas?

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
Quentin Tealrod
  • 309
  • 3
  • 14
  • 4
    post MyCollection code. – David Haim Jul 23 '15 at 08:23
  • 4
    It seems like you forget to declare your begin and end methods const. You should declare a begin method that returns a non const iterator and a const begin method that returns a const iterator. – geoalgo Jul 23 '15 at 09:22
  • I also smell something funny with regards to the presence / absence of `` in that error message... why is `begin()` seeing a non-templated `this`? – DevSolar Jul 23 '15 at 09:24
  • I've edited my post with the functions. Did I forget smtg ? thx – Quentin Tealrod Jul 23 '15 at 09:45
  • 3
    you probably meant to have `typename std::list::const_iterator begin() const` instead of `typename std::list::const_iterator cbegin() const`. range-based for loop looks up for `begin`/`end` names, not `cbegin`/`cend`, they were added for convenience (forcing const iterators) – Piotr Skotnicki Jul 23 '15 at 09:47
  • It does work with begin() and end() constant functions. I seem wired to me that the range-based for loops only looks up with begin & end function instead of cbegin & cend, but I have no other choice than to accept it :)... Thanks all of you ! – Quentin Tealrod Jul 23 '15 at 09:59

1 Answers1

4

A range-based for loop (for a class-type range) looks up for begin and end functions. cbegin and cend are not considered at all:

§ 6.5.4 [stmt.ranged]/p1 *:

[...]

  • if _RangeT is a class type, the unqualified-ids begin and end are looked up in the scope of class _RangeT as if by class member access lookup (3.4.5), and if either (or both) finds at least one declaration, 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 in the associated namespaces (3.4.2). [ Note: Ordinary unqualified lookup (3.4.1) is not performed. — end note ]

For a const-qualified range the related member functions must be const-qualified as well (or should be callable with a const-qualified instance if the latter option is in use). You'd need to introduce additional overloads:

typename std::list<T>::iterator begin() {
    return objects.begin();
}

typename std::list<T>::const_iterator begin() const {
//                                            ~~~~^
    return objects.begin();
}

typename std::list<T>::const_iterator cbegin() const {
    return begin();
}

typename std::list<T>::iterator end() {
    return objects.end();
}

typename std::list<T>::const_iterator end() const {
//                                          ~~~~^
    return objects.end();
}

typename std::list<T>::const_iterator cend() const {
    return end();
}

DEMO


* the wording comes from C++14, but the differences are unrelated to the problem as it is stated

Community
  • 1
  • 1
Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160