Search code examples
c++arraysclasstemplatesbubble-sort

Binary '[': no operator found which takes a left hand operand of type 'const SortableVector<int>'


So I ran into this issue as I was coding for the class I'm currently in, I believe the code should run fine but this came up: Binary '[': no operator found which takes a left hand operand of type 'const SortableVector' I'm not quite sure how to tackle this, any suggestions?

I ended up looking at No '==' operator found which takes a left-hand operand of const Type to see if I could find a solution in there however I did not, it seems my issue is stemming from something that I don't personally see.

#include <iostream>
#include "SortableVector.h"
using namespace std;

int main() {
    const int SIZE = 10;

    SortableVector<int> intTable(SIZE);

    for (int x = 0; x < SIZE; x++) {
        int z;
        cout << "Please enter a number with no decimals: ";
        cin >> z;
        intTable[x] = z;
    }

    cout << "These values are in intTable:\n";
    intTable.print();

    intTable.sortInt(intTable, SIZE);

    cout << "These values in intTable are now sorted: ";
    intTable.print();

    return 0;
}




//SortableVector.h
#include <iostream>
#include <cstdlib>
#include <memory>
#include <vector>
using namespace std;

struct IndexOutOfRangeException {
    const int index;
    IndexOutOfRangeException(int ix) : index(ix) {}
};
template<class T>
class SortableVector {
    unique_ptr<T[]> aptr;
    int vectorSize;
public:
    SortableVector(int);
    SortableVector(const SortableVector &);

    int size() const { return vectorSize; }
    T &operator[](int);
    void sortInt(SortableVector<int>, int);
    void print() const;
};

template<class T>
SortableVector<T>::SortableVector(int s) {
    vectorSize = s;
    aptr = make_unique<T[]>(s);
    for (int count = 0; count < vectorSize; count++) {
        aptr[count] = T();
    }
}

template<class T>
SortableVector<T>::SortableVector(const SortableVector &obj) {
    vectorSize = obj.vectorSize;
    aptr = make_unique<T[]>(obj.vectorSize);
    for (int count = 0; count < vectorSize; count++) {
        aptr[count] = obj[count];
    }
}

template<class T>
T &SortableVector<T>::operator[](int sub) {
    if (sub < 0 || sub >= vectorSize) {
        throw IndexOutOfRangeException(sub);
        return aptr[sub];
    }
}

template<class T>
void SortableVector<T>::sortInt(SortableVector<int> x, int z) {
    int i, j;
    int temp = 0;

    for (i = 0; i < z - 1; i++) {
        for (j = 0; j < z - 1; j++) {
            if (x[j] > x[j + 1]) {
                temp = x[j];
                x[j] = x[j + 1];
                x[j + 1] = temp;
            }
        }
    }
}

template<class T>
void SortableVector<T>::print() const {
    for (int k = 0; k < vectorSize; k++) {
        cout << aptr[k] << " ";
    }
    cout << endl;
}

Solution

  • Your operator[] returns a reference to the element, which will allow people to directly change the element. The problem happens when you try to use the operator on a const object (when you used const references to pass things to functions). This will allow someone to change the object through that reference returned by operator[], which breaks const-correctness and therefore is not allowed.

    In case you're sill confused, let's say you have some class like this:

    class Foo
    {
    private:
        int numbers[100];
    public:
        int& operator[](const int & pos)
        {
            return numbers[pos];
        }
    };
    

    This works fine for creating an object and using the bracket operator to access the elements. However, when you try to create a const object:

    const Foo f;
    

    You can do something like this:

    f[3] = 5;
    

    operator[] returns a reference, which can be used to directly change the data stored in f. f is declared as const though, so this must not happen and the compiler gives an error.

    The solution would be to have two versions of operator[], overloaded by their const-ness:

    class Foo
    {
    private:
        int numbers[100];
    public:
        int& operator[](const int &pos)
        {
            return numbers[pos];
        }
        const int& operator[](const int &pos) const
        {
            return numbers[pos];
        }
    };