Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to overload the operators to call a setter function on an operator[] call?

How can I overload the operators of a class, so that using syntax of

classInstance[index] = value;

performs

classInstance.cfgfile.Write(index,value)

background info; feel free to skip.

The application we develop uses a memory-mapped access to a segment of NVRAM - actually, mapped are just two registers, address and data. You write to the address register, then either write or read the data register. After initialization, the reads and writes are performed by a simple [] overload of the class holding the reference to the segment of memory. You refer to the instance's [] giving a namespaced index of the cell you want to read and write and it does its thing.

int& IndirectMemory::operator[](RTCMemIndex idx)
{
    *midx_reg = idx;
    return *mdata_reg;
}

(code stripped of irrelevant elements like mutexes and sanity checks).

Everything works fine... as long as the NVRAM works fine. This specific chip is out of production, and the ones 'out in the wild' began dying of old age currently. Their functionality is of low significance to our use, and we could shift their role to the flash memory with nearly no impact (just a little more flash wear) if the chip goes corrupt. Thing is we want to use the flash record using our config format, which uses getters and setters.

int TCfgFile::ReadKey(std::string Key);
void TCfgFile::WriteKey(std::string Key,int data);

And in many places of the code we have calls to NVRAM through IndirectMemory[Some_Register] = Some_Value; writting assorted things that change frequently and we want to persist through reboot. I'd like to retain this syntax and behavior, but be able to write to the file if NVRAM is detected to be corrupted or manually disabled through a config entry.


The net is rife with examples of using operator[] for setting given value just by returning the reference to it. For example:

unsigned long operator [](int i) const    {return registers[i];}
unsigned long & operator [](int i) {return registers[i];}

In that case if I call, say, reg[3] = 1; the [] will return a reference to the element#3 and the default operator= will write to the reference just fine.

But since I can't return a reference to a key in the file (.WriteKey() just performs a complete write, returning success or error), and operator= doesn't take an index, I'm afraid this simple option won't help.

like image 414
SF. Avatar asked Jan 21 '19 14:01

SF.


1 Answers

You can use a proxy class to solve this. Since value can't be passed into classInstance we need to make an object that operator[] can return that will get the value of value and knows which instance to apply the operation to. Using

struct Proxy
{
    classInstance_type& to_apply;
    index_type index;
    Proxy(classInstance_type& to_apply, index_type index) : to_apply(to_apply), index(index) {}
    Proxy& operator=(value_type const & value)
    {
        to_apply.cfgfile.Write(index,value)
        return *this;
    }
};

your class's operator[] would look like

Proxy operator[](index_type index)
{
    return Proxy{*this, index};
}

and then when you do classInstance[index] = value; you call Proxy's operator= which has a reference to the object to call, the index to use, and the value you also need.

like image 180
NathanOliver Avatar answered Oct 10 '22 23:10

NathanOliver