views:

114

answers:

4

I have two very different behaviors for reads and writes. In the event of reads, I want to copy a buffer of a rather hard to extract data structure. On writes, I will just write unbuffered to the structure.

Up to now, I have been using operator[] to do access, so for the sake of polymorphism I'd like to continue doing so.

So my question is this: When a access is made, which version is called? My notion is that the const is called for reads, and the non-const for writes. In that case, this is a simple thing to implement. Otherwise, it may be more tricky.

+3  A: 

The overload resolution is based on the this parameter, that is - on the constness or lack of constness of the object You call the operator[] on.

Maciej Hehl
A: 

It depends on what you're "assigning" to:

const type& x=X[i]

will call the const version of the function

type& x=X[i]

or

X[i]=x

will call the non const version. And finally, a simple assignment

type x=X[i]

There's no real way to say that one's a "read" and the other's a "write". Basically the const version will return a view into your data where updates are not reflected. The non-consts version will return a view into your data where updates can be reflected but there's no semantics to provide a refresh after a write.

miked
+7  A: 

To accomplish what you want, you generally need to have operator[] return a proxy, and overload operator= and operator T (where T is the original type) for that proxy type. Then you can use operator T to handle reads, and operator = to handle writes.

Edit: the basic idea of a proxy is pretty simple: you return an instance of an object that acts in place of the original object. For the moment, this is going to have really trivial semantics (just read and write a char at a specified index in a vector); in your case, the logic inside of the operator= and (especially) operator T will apparently be more complex, but that has little or no effect on the basic structure.

#include <vector>

class X {
    std::vector<char> raw_data;

    class proxy { 
        X &parent;
        int index;   
    public:
        proxy(X &x, int i) : parent(x), index(i) {}

        operator char() const { return parent.raw_data[index]; }

        proxy &operator=(char d) { 
            parent.raw_data[index] = d; 
            return *this;
        }
    };
public:
    X() : raw_data(10) {}
    proxy operator[](int i) { return proxy(*this, i); }
};

#ifdef TEST

#include <iostream>

int main() {
    X x;
    for (int i=0; i<10; i++)
        x[i] = 'A' + i;

    for (int i=0; i<10; i++)
        std::cout << x[i] << "\n";
    return 0;
}
#endif
Jerry Coffin
A: 

Since the behavior between reads and writes is so different, you might want to at least consider NOT overloading operator[] but instead making separate read and write methods.

To answer your question, it's based on the const-ness of the object upon which you're operating. It doesn't know what you're going to do with the result of the operator so it has only one thing to work with, the object on which you're calling the operator. If the object is non-const it will always call the non-const (write) version of your operator. You can get around this by const_casting const onto the object, but separate methods seems like a better approach.

Mark B