EDIT I caused some confusion by referring to rvalues. I provide an example of what I want to do at the bottom.
I want to separate these two calls:
obj[key] = value;
value = obj[key];
I tried using two operator[] overloads, hoping the const method would be used exclusively for rvalues, and the non-const version would be exclusively used for lvalue calls.
const ValueType& operator[] (const KeyType& key) const;
ValueType& operator[] (const KeyType& key);
But my const version was only ever called when this
was const.
I tried using a wrapper that would override op=
and op ValueType
.
BoundValue<KeyType, ValueType> operator[] (const KeyType& key)
// later in BoundValue
operator ValueType() const
const V& operator= (const V& value)
This worked marvelously...until I hoped op[]
would implicitly cast for a template argument deduction (which is not allowed).
// example failure of wrapper
// ValueType is string, std::operator<< from string is a template method
cout << obj[key];
For this specific case, I could define my own ostream methods.
ostream& operator<< (ostream& os, const BoundValue<K, V>& bv);
But my type would similarly fail in any user defined template argument (seems likely).
I can think of two work arounds, both of which greatly reduce the sweetness of the syntax sugar I am trying to provide:
// example where ValueType is string
cout << static_cast<string>(obj[key]);
or,
// added to BoundValue
const ValueType& Cast() const
// later in use
cout << obj[key].Cast();
Example of desired use case
Map<int, string> m;
m[1] = "one";
try
{
string one = m[1];
cout << "one is set: " << one << endl;
string two = m[2];
cout << "two is set: " << two << endl;
}
catch (...)
{
cout << "An exception was thrown" << endl;
}
Expected output:
one is set: one
An exception was thrown
And how/why is the exception thrown? I can check if the key exists, and throw if it doesn't. If I can't separate the get from the set, I don't know when access for a key is allowed.