2

I have classes for linear algebra, specifically vectors and matrices. These contain among others std::vectors (or std::maps) as their 'data' fields.

Iterating over these in a range based for loop is easy. But I'd like to make these fields private and make iterating over my custom classes more natural, such that I can do range based for loops over the class itself.

I tried looking at the function definition of std::vector<>.begin() and such. Then I tried to implement it in such a way that all the iterator objects are forwaded from the std::vector<> fields, but to no avail. When I try to iterate over a constant instance of my class, with the following example;

int main() {

    AlgebraLib::Vector A(4, true);
    A[0] = 4;
    A[1] = 5;
    A[2] = 6;
    A[3] = 7;

    for (auto &&item : A) {
        std::cout << item << std::endl;
    }

    const AlgebraLib::Vector B = A;

    for (auto &&item : B) {
        std::cout << item << std::endl;
    }

    return EXIT_SUCCESS;
}

... I get the following compiler error;

error: passing ‘const AlgebraLib::Vector’ as ‘this’ argument discards qualifiers [-fpermissive]
 for (auto &&item : B) {

Basically, all iterators are defined like this:

std::vector<double>::iterator Vector::begin() {
    return _VectorContents.begin();
}

std::vector<double>::iterator Vector::end() {
    return _VectorContents.end();
}

std::vector<double>::reverse_iterator Vector::rbegin() {
    return _VectorContents.rbegin();
}

std::vector<double>::reverse_iterator Vector::rend() {
    return _VectorContents.rend();
}

std::vector<double>::const_iterator Vector::cbegin() const noexcept{
    return _VectorContents.cbegin();
}

std::vector<double>::const_iterator Vector::cend() const noexcept{
    return _VectorContents.cend();
}

std::vector<double>::const_reverse_iterator Vector::crbegin() const noexcept{
    return _VectorContents.crbegin();
}

std::vector<double>::const_reverse_iterator Vector::crend() const noexcept{
    return _VectorContents.crend();
}

And in my header Vector.hpp:

    // Iterators
    std::vector<double>::iterator begin();

    std::vector<double>::iterator end();

    std::vector<double>::reverse_iterator rbegin();

    std::vector<double>::reverse_iterator rend();

    std::vector<double>::const_iterator cbegin() const noexcept;

    std::vector<double>::const_iterator cend() const noexcept;

    std::vector<double>::const_reverse_iterator crbegin() const noexcept;

    std::vector<double>::const_reverse_iterator crend() const noexcept;

I feel like I'm missing something here? I'm relatively new to C++, and I work at the moment with C++11.

Lars Gebraad
  • 163
  • 1
  • 7
  • What is `row`? What is `_VectorContents`? Please create a [Minimal, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve) to show us. – Some programmer dude Aug 17 '17 at 09:59
  • 1
    On an unrelated note, all symbols beginning with an underscore and followed by an upper-case letter (like for example `_VectorContents`) are reserved in all scopes. Please see [this old question and its answers](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) for more information. – Some programmer dude Aug 17 '17 at 10:02
  • Sorry for that, should've made a better example. And thanks for the comment on the underscore, I did actually use it for all my member variables. – Lars Gebraad Aug 17 '17 at 10:12

1 Answers1

3

The problem is that B is const, but the range-for loop only uses begin and end (not cbegin and cend) and your begin and end functions have no overloads that are const. This is a problem because only functions that are marked as const can be called on const objects.

The solution is simple: Just add such overloads

std::vector<double>::const_iterator begin() const;

std::vector<double>::const_iterator end() const;

The implementation of these overloads will be just the same as for the non-const functions.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621