Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Operator[] C++ Get/Set

Tags:

c++

I'm having trouble with telling the difference between get and set for the operator[]. I need to tell the difference between these function calls.

cout << data[5];
data[5] = 1;

I googled it, and the answers I found still didn't help. People suggested making the signatures for the methods different by adding const. I did that, and they still both called the same method.

There are the signatures I had used:

const T& operator[](unsigned int index) const;
T& operator[](unsigned int index);

What am I doing wrong?

like image 444
Taztingo Avatar asked Oct 07 '13 05:10

Taztingo


2 Answers

The solution is to use a "proxy" object that will delay the actual operation:

#include <vector>
#include <iostream>

template<typename T>
struct MyArray {
    std::vector<T> data;
    MyArray(int size) : data(size) {}

    struct Deref {
        MyArray& a;
        int index;
        Deref(MyArray& a, int index) : a(a), index(index) {}

        operator T() {
            std::cout << "reading\n"; return a.data[index];
        }

        T& operator=(const T& other) {
            std::cout << "writing\n"; return a.data[index] = other;
        }
   };

   Deref operator[](int index) {
       return Deref(*this, index);
   }
};

int main(int argc, const char *argv[]) {
    MyArray<int> foo(3);
    foo[1] = 42;
    std::cout << "Value is " << foo[1] << "\n";
    return 0;
}

Simple const-ness cannot be used because you may need to read from a non-const instance, that is the reason for which you must delay the operation: the assignment happens "after" the access and the compiler doesn't tell you if the access will be later used as a target for assignment or not.

The idea is therefore that on access you just store away the index that has been requested and wait to know if a reading or a writing operation is happening. By providing an implicit conversion operator from the proxy to T you know when a reading operation occurs, by providing an assignment operator to the proxy from T you know when writing occurs.

like image 80
6502 Avatar answered Nov 11 '22 19:11

6502


The const version means that if the object on which it is called is const, you are allowed to call that version of the [] operator, and only that version.

But if the object is not const, then both versions of the [] operator can be called, but the compiler will select the non-const version. In other words, for a non-const object, the non-const version of the operator can act as either the "setter" or "getter". This is why the same version is called in both cases in your example, because your data object is not const.

You would have to do something like this:

const Data& data_cref = data;
cout << data_cref[5];  // calls the const version of operator[]

Data& data_ref = data;
data_ref[5] = 1;       // calls the non-const version of operator[]
like image 4
Mikael Persson Avatar answered Nov 11 '22 18:11

Mikael Persson