I was designing a kind of a parser when I thought that it would be nice to have an operator overload like this: operator[]=(subscipt_type s, rvalue_type val)
. For example we have a class:
//collection of Foos
class FooCollection
{
public:
//assume class Foo is defined
Foo& operator[]=(int i, const Foo& val);
//.....
};
And we need to assign a subscripted value:
Foo value;
FooCollection c;
c[42] = value;
then the last line of this code will resolve into
c.operator[]=(42,value);
The advantage of this operator in comparison to existing Foo& operator[](int i)
is that we know the rvalue of assignment during the subscripting, so we can do something that could be unwished in ordinary operator=
.
For example, I tried to design a parse tree consisting of polymorphic nodes with minimal interface. This is the basic node class, all other node types are inherited from it:
class AnyNode
{
public:
virtual AnyNode& operator=(const AnyNode& op)
{
//Takes almost no actions here.
//Overloaded in each subclass to take some sensible actions
}
virtual AnyNode& operator[](int i)
{
//Returns special null value of AnyNode type.
}
};
The AnyNode class is not pure virtual, so it's possible to construct AnyNode
objects. One of the syntax elements that I try to parse is a python-like list, which may contain heterogenous values and may be subscripted with an integer. A class for it:
class ArrayNode : public AnyNode
{
public:
AnyNode& operator[](int i)
{
//Returns a reference to i-th element
}
};
So what will happen when we try to assign something to the array cell, which was not assigned before and it's concrete type was not defined? AnyNode& operator=(const AnyNode& op)
from class AnyNode
will be called and no actions will be taken. But I want to know the AnyNode&
rvalue just after subscripting, so that it could be possible to deduce it's concrete type with RTTI and take some sensible actions. Subscript/assignment operator could look like this:
AnyNode& operator[]=(int i, const AnyNode& val)
{
//AnyNode::getType() is provided and it returns a value of the predefined enum.
//stor is an underlying container that holds pointers to AnyNode,
//assume it's possible to reference stor[i].
//NodeNumber is another subclass of AnyNode.
switch(val->getType())
{
case nodetypeNumber:
stor[i] = new NodeNumber();//Also we may need to delete stor[i] before new allocation.
//Process further specific initialization of stor[i].
break;
//................
}
//Or we could use dynamic_cast instead of switch(val->getType())
}
I suppose, such kind of subscipt/assignment operator can be easily and consistently built into language. Moreover, it delimits the pieces of code which execute when the subscripted expression is an lvalue and when it's an rvalue: with it the usual subscript operator should be called only when the subscription is rvalue. Of course, if the proposed operator is not defined, but a operator[]
is defined, the code should execute in a usual way.
So my questions are: what pitfalls could I miss about this operator and why does it not included into the language? Can it break language consistency in any way or can it bring up any ambiguity into the language?