Reputation: 53
I am trying to implement the operator [] that is to be used once for Set and once as Get, i need to differentiate between the two cases, as in the case of get, i need to throw an exception if the returned value is equal to -1; whereas in the case of Set i just overwrite the value. appple[2] = X; y=apple[2];
I dont know how to differentiate between the two modes, my function signature is:
double& Security::operator[](QuarterType index){
if(index<0 || index>MAX_QUATERS){
throw ListExceptions::QuarterOutOfBound();
}
return evaluation[index].getValueAddress();
}
Upvotes: 5
Views: 612
Reputation: 41096
C++ does not easily allow distinction of
appple[2] = X;
y=apple[2];
The most common solution is to return a proxy object:
struct AppleProxy
{
Security & obj;
unsigned index;
AppleProxy(Security &, unsigned) : ... {}
operator double() // your getter
{
return obj.GetAt(index);
}
operator=(double rhs)
{
obj.SetAt(index, rhs);
}
}
AppleProxy operator[](unsigned index) { return AppleProxy(*this, index); }
Proxy require significant attention to detail, I've omitted const
correctness, life-time management, taking-the-address-of (double & x = apple[2]; x = 17;
), etc.
Due to the pitfalls, I tend to avoid them.
Upvotes: 4
Reputation:
Unlike languages such as python or C#, C++ doesn't offer get and set modes for its operators. Thus, you have to write operator[]
so that it returns an object that does the right thing when used in any context you want it to be used, which usually means a reference.
Note I said usually; there are other things you can do, such as return an instance of a class with the following members:
struct proxy
{
operator double() const;
void operator=(double x);
};
If this proxy object is used in a context expecting a double, it will invoke the implicit conversion operator, which is implemented to do your get operation. Similarly, if someone assigns to the proxy object, it will invoke the assignment operator, which is implemented to do your set operation.
(note that the proxy will probably need a reference to your Security
object)
This approach is not without its difficulties, though; since your return value is not of type double
or double&
or similar, it can cause confusion with overload resolution, especially with template functions, and cause a lot of confusion when used with auto
. And your proxy object can't even be used in a context that needs a double&
!
Thus, this is something of a last resort, when you're backed into a corner and have to do access in terms of an operator[]
that pretends to be working with double
. Before you resort to this, you really should seek other options, such as:
Security
objects can just return references to double
s rather than needing more complicated get and set operations. (e.g. change the invariants so there isn't exceptional data, or make the error handling happen somewhere else)operator[]
that has various nontrivial behaviors, rather than expecting to use operator[]
to read/write double
objects.Upvotes: 7
Reputation: 2075
You can return a proxy object from your [] operator that has an implicit conversion operator double
for the target type and operator =
. If the conversation operator is called and your value is -1 you throw, if the assignment is called you assign.
Upvotes: 1
Reputation: 27365
I am trying to implement the operator [] that is to be used once for Set and once as Get
It cannot be done. You can implement multiple versions of the operator, with different signatures (that is, with const and non-const versions) but they will not be called correctly.
Instead, consider implementing set and get functions with the functionality you require.
Upvotes: 4
Reputation: 234645
The "Get" version could take a const
reference and be marked as const
:
const double& Security::operator[](QuarterType index) const
The "Set" version could be written as you currently have it:
double& Security::operator[](QuarterType index)
At times when you need to force the const
version to be called, you can const_cast
your object to a const
type. (Don't do it the other way round though: the behaviour of casting away const
-ness is undefined if the original object was const
).
But personally I see this as unnecessarily complicated. It might be more practical to move away from operator overloading and write separate get
and set
functions instead. You could do something with the QuarterType
class: perhaps imbuing a traits system into it which allows the function to deal with specific QuarterType
instances accordingly. But that's probably no better than having separate functions with different names.
(If QuarterType
is a large object, then consider passing const QuarterType&
. That will prevent a value copy from being taken.)
Upvotes: -1
Reputation: 119
Look over operator overloading article on cppreference.com. The Array subscript operator section explains what you need exactly:
User-defined classes that provide array-like access that allows both reading and writing typically define two overloads for
operator[]
: const and non-const variants:struct T { value_t& operator[](std::size_t idx) { return mVector[idx]; }; const value_t& operator[](std::size_t idx) const { return mVector[idx]; }; };
If the value type is known to be a built-in type, the const variant should return by value.
(continued)
So, you should define double Security::operator[](QuarterType index) const
, instead of const double& Security::operator[](QuarterType index) const
.
Upvotes: -1