views:

53

answers:

3

I would like to create a C++ object to wrap the RAM of an external peripheral device. I'm trying to set up something like the following:

Peripheral p;

p[4] = 10;

int n = p[5];

To do this I need to read or write to the peripheral whenever an array element is accessed. I cannot work out how to do this using operator overloading etc. I can return an "accessor" object that can be used as an lvalue in the second line:

PeripheralAccessor Peripheral::operator[](int i);

or I can define a "simple" operator that can be used to read an int from the peripheral on the third line:

int Peripheral::operator[](int i);

but I cannot get the two to coexist to give both read and write access to the peripheral. I can define this second operator as a const (rvalue) operator, but it will ONLY then be called for a const instance of the class, which isn't enough for my needs...

Hopefully I've explained what I'm trying to achieve here clearly; can anybody suggest how I should be doing it (or indeed whether it is possible)?

+3  A: 

The usual way to handle this is to use a proxy object:

class register_proxy { 
public:
    register_proxy &operator=(int value) { 
        write_value(value);
    }

    operator int() {
        return read_value();
    }
};

class peripheral { 
    register_proxy registers[4];
public:

    register_proxy &operator[](int reg_num) { return registers[reg_num]; }
};

I've left out some details (like how you tell each register_proxy what actual register number to read/write -- usually by passing an argument to the ctor). In any case, the general idea is pretty simple: operator[] returns a reference to a proxy object. The proxy object's operator int (or whatever type it takes, of course) gets invoked when you use it on the right side of an assignment. The proxy object's operator= gets invoked when it's on the left side of the assignment, so you're trying to write a value there.

Jerry Coffin
+1, was writing exact same thing.
Nikolai N Fetissov
@Nikolai same here. </slow>
Cogwheel - Matthew Orlando
Brilliant, thanks. It was the fact that you could do:operator int()that I hadn't worked out.
Jonny
+1  A: 

Since you can't overload based on return type, you have to choose one or the other (and you can't choose int, 'cause then you don't get the lvalue behavior). However, you can give PeripheralAccessor an automatic conversion to int.

Edit: Jerry beat me. With code even.

Cogwheel - Matthew Orlando
+2  A: 

Give your "PeripheralAccessor" an implicit conversion operator for int:

operator int () const;
Noah Roberts