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.
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.