operator[][] C++ - c++

I'd like to overload operator[][] to give internal access to a 2D array of char in C++.
Right now I'm only overloading operator[], which goes something like
class Object
{
char ** charMap ;
char* operator[]( int row )
{
return charMap[row] ;
}
} ;
It works ok.. Is it possible to override operator[][] though?

Don’t try to do that – as others have said, overloading operator [] the way you do actually provides the [][] syntax for free. But that’s not a good thing.
On the contrary – it destroys the encapsulation and information hiding of your class by turning an implementation detail – the char* pointer – to the outside. In general, this is not advisable.
A better method would be to implement an operator [,] which takes more than one argument, or indeed an operator [][]. But neither exists in C++.
So the usual way of doing this is to ditch operator [] altogether for more than one dimension. The clean alternative is to use operator () instead because that operator can have more than one argument:
class Object
{
char ** charMap ;
char& operator ()(int row, int column)
{
return charMap[row][column];
}
};
For more information, see the article in the C++ FAQ Lite.

There is no operator [][]: that's two [] operations in a row. You could:
Have Object::operator[] return an object of a second class representing a row, which has its own operator[] method that takes a column number;
Write a get(int row, int column) method and use that instead of operator overloading. I'd recommend this unless your object absolutely has to behave like an array.

There is no operator[][]. Evaluating a[x][y] first calls operator[] on a, and then operator[] again on the result of that.
So the operator[] of your object has to return another object with its own operator[], which then will access the requested value.

As far as I know there is no such thing as operator[][]. What you can do is you could return from your operator[] method something that has overloaded operator[].
Actually you are doing it now, because you return char* which can be indexed using [] again.

There is no [][] operator. What actually happens is that the second [] operates on the variable returned by the first []. Because there is already that functionality, it would create ambiguity were there to exist a [][] operator.
For example: let's say you have a variable x of some type T.
T x = new T();
If we use the [] operator, let's say a variable of other type Q is returned:
Q y = x[0];
And then using the [] operator on a variable of type Q might return a variable of type R:
R z = y[0];
Therefore x[][] returns a variable of t ype R.
Let's say we actually were able to overload [][] for type T such that it returned a type S:
S a = x[0][0];
The compiler would have no way of knowing if it should use the [][] operator on x to return a type S variable, or use the [] operator twice in a row to return a type R variable. This is the ambiguity I mentioned above.
Your best bet if you're stuck on using square brackets is to have operator[] return a variable which also has [] overloaded (or perhaps a variable of the same type, with a flag set), and have that initially returned variable deal with the second [].
But the best solution here (as mentioned already in another answer) is to use a different operator such as ().

Related

What is this "operator" block of code in c++ class

I'm using someone's class for bitmaps, which are ways of storing chess positions in 64-bit bitsets. I was wondering what the part with auto() operator does. Is "auto" used because it returns one bit, which is why a return-type isn't specified for the function? I get that it checks that x and y are in the bounds of the chess board, and asserts an error if they aren't. I also understand that it returns a bit that corresponds to the x,y value pair for the bitset. I also don't get why the function is defined like it is, with an extra pair of parentheses. Any help is appreciated!
class BitBoard {
private:
std::bitset<64> board;
public:
auto operator()(int x, int y) {
assert(0<=x && x<=7);
assert(0<=y && y<=7);
return board[8*y+x];
}
}
};
The "extra" pair of parentheses are because you're defining operator(), which lets instances of your class behave like functions. So if you had a:
BitBoard board;
you could get the value for x=3, y=5 by doing:
board(3, 5)
instead of having a method you call on the board explicitly, like board.get_bit_at(3, 5).
The use of auto just means it deduces the return type from std::bitset<64>'s operator[]; since the method isn't const qualified, this means it's just deducing the std::bitset::reference type that std::bitset's operator[] uses to allow mutations via stuff like mybitset[5] = true;, even though you can't give "true" references to single bits. If reimplemented a second time as a const-qualified operator(), e.g.:
auto operator()(int x, int y) const {
assert(0<=x && x<=7);
assert(0<=y && y<=7);
return board[8*y+x];
}
you could use auto again for consistency, though it doesn't save any complexity (the return type would be bool in that case, matching std::bitset's const-qualified operator[], no harder to type than auto).
The choice to use operator() is an old hack for multidimensional data structures to work around operator[] only accepting one argument; rather than defining operator[] to return a proxy type (which itself implements another operator[] to enable access to the second dimension), you define operator() to take an arbitrary number of arguments and efficiently perform the complete lookup with no proxies required.
operator() is the name of the function, which is then followed by another pair of parentheses listing the arguments. It is the function-call operator and overloading it allows you to make objects that act like functions/function pointers. In this case, it allows:
BitBoard thing;
thing(i, j); // looks like a function!
In this particular case, it's being used for indexing (like a[i]) but the subscript operator operator[] doesn't allow multiple indexes and the function-call operator does. So it was pretty common to see this for multi-dimensional arrays.
However, the new "preferred" style for multiple indexes in C++ is to pass a list to the subscript operator:
BitBoard thing;
std::cout << thing[{i, j}];
This would be accomplished by operator[](std::array<int, 2> xy).
But the author of this class has chosen the old way, that looks like a function call.
Overloaded operator() is also what makes lambda expressions tick inside.

Why is `operator[]' needed when 'operator double*` seems to do the job

operator[] seems superfluous since operator double* seems to be enough.
Here is my code:
struct CStandardData
{
inline operator double* () { return m_standardData; }
//inline double& operator [] (size_t ix) { return m_standardData[ix]; }
size_t m_standardDataRefCnt{ 0 };
double m_standardData[1];
} sd;
I use sd in all kinds of different situations including double *a = sd, sd[x] = 5.0, sd[x] >= sd[y], etc. and regardless whether I have the operator [] commented out or defined, the code seems to work correctly.
In what situations would it be necessary to have operator []?
I probably should have added a bit of context:
I used the internal data double sd[], which was dynamically allocated, throughout a large base of code >5000 lines. Then I needed to add allocation reference counting to this double array, because of a need to copy the object it was in, and pass a copy to the user (the double sd[] is >10000 elements so I did not want extra copies made). This is the scheme that I devised to do that without having to modify the vast base of code using it, but was not sure if omitting operator [] could lead to any problems.
In what situations would it be necessary to have operator []?
In situations when you want your object act as a container but not a pointer. For example this code:
MyContainer cnt;
if( cnt ) // something
will compile if you define operator double *, but I do not want this code to compile in general for my container, because it does not make any sense.
sd[x] = 5.0 does not have a context for compiler to apply implicit user-defined conversion of CStandardData to double * prior to invoking operator []. If such a conversion is performed explicitly then there will be no need for overloading operator []: static_cast<double *>(sd)[x]
Also overloading operator [] seems like a good idea anyway because it will allow you to verify that passed index is valid.

overload operator[ ] for a non-class type

I am wondering if there is a way to overload operator[] for a non-class type in C++.
Basically, there is a data type which is a pointer (CFDictionaryRef from CoreFoundation). But it's not a class (i know that overloading operator[] for a specific class is allowed). I know how to access each element inside the CFDictionaryRef (for example, by using CFDictionaryGetIndex(CFIndex index); ). I want to make it simplified so that I don't have to write that function call every time. I want to overload the operator[ ] for CFDictionaryRef. But since it's not a class, from what I see, it's not possible.
Anyone got any suggestions?
You're right, it's not possible to overload operators on non-user-defined types.
What you might do is wrap the pointer in a class and overload the operators on the class itself. Since you can only overload operators on class types, this is the only option.
class CFDictionaryRefWrapper {
public:
CFDictionaryRefWrapper(CFDictionaryRef r) : dref(r) { }
CFDictionaryRef dref;
Type operator[](unsigned int index) {
/* do whatever with dref */
}
};
This also has the advantage of being able to automatically manage the lifetime of the pointer (RAII) if you need to do that.
No, you cannot overload the [] operator for a pointer type, or any other built-in type. In fact, ptr[N] already is a shorthand for *(ptr + N).
You'd need to define your own class which wraps the pointer if you want to overload the [] operator.

Combined Operator Overloading in C++?

Is it possible to overload operators in such a way that you can capture a specific combination of them? For example lets say I have a custom object myObject of type MyType where [] is already overloaded to pass such calls down to a map object. That said, in the case of the following code:
int value = myObject["someProp"];
I'm already overloading [] but in this case I'd like to know when [] is being called on the object in an assignment, with a reference to the type of object that the property lookup is to be assigned to. This way I can cast the value coming out of the dynamic property lookup and so on and so forth. Any input is appreciated!
For more insight into exactly what I'm trying to accomplish, see this related question of mine.
No, you can't overload on the return type, or on the context in which the call appears (e.g. in an assignment etc).
You could, however, return a proxy object that would have a bunch of overloaded conversion operators. Without seeing what you intend to do, it's hard to say how far you might be able to get with this approach, or whether it's even a sane thing to do.
If you want type deduction for things like this, your best bet is to overload operator() instead, and pass in the thing you're going to be assigning to as a dummy parameter, i.e.:
MyType myObject;
int value = myObject("someProp", value);
I've made something like this work pretty well in the past. In particular, see e.g.:
https://github.com/sgolodetz/hesperus2/blob/master/source/engine/core/hesp/objects/base/ObjectManager.tpp
In principle, it's rather straightforward to do: all that is needed is
for your operator to return a proxy which then overloads the operators
you want to catch. In practice, it can cause more than a few problems;
readers will expect (a op1 b) op2 c to have
the same semantics as T tmp(a ip1 b); tmp op2
c. There are some common exceptions, however:
The operator[] in a multi-dimensional array will often return a
proxy which defines an operator[] itself, in order to support [][]
correctly.
More generally, a container which for whatever reasons needs to know
when a value is modified will have an operator[] which returns a
proxy; within the proxy, assignment is defined as setting the value in
the owning container, and there will be a convertion operator to the
value type, for use in rvalue contexts. Of course, this means that
things like m[i][j].funct() don't work; typically, however, this sort
of thing is used for matrices of numeric types, where member functions
aren't that relevant.
In contexts where it is desirable to support overload resolution based
on the target type (your example), the function can return a proxy with
overloaded conversion operators. You want to be extremely careful with
this—overloaded conversion operators are often a recipe for
overload resolution ambiguities&rdash;but there are enough exceptions
that this situation bears mentionning. (Important, here, is that the
results of the operator will amost always be used to intialize or to
assign to a specific object, the type of which determines which
conversion operator will be called.)
BTW: I might mention that in the example you give, there is no
assignment; it is a classical initialization. In this case, defining
the operator[] to return a proxy which defines operator int() const
would do the trick very well. Before going this route, however, you
should very definitely consider all of the use cases of your class, and
ensure that there are none in which the actual target type is ambiguous.
The other answers are basically correct that you can't do it. aix hints at a solution of a custom return type with overloaded conversion operators, but rightly indicates it isn't a sane thing to do. I've ventured down this path quite often and ultimately implicit conversions, and sequences of conversions, and ambiguities will bite you in you in the behind.
I've had a need of this quite often though. Ultimately I end up going for a series of overloaded functions, or templates, depending on your needs, perhaps like this:
void lookup( int& v, char const * name );
void lookup( double& c, char const * name );
In the template case I created global converters and did the below member function:
template<T>
void lookup( T&v, char const* name ) { v = convert<T>( get(name) ); }
If you want to keep the return value as the lookup you'll have to explicitly call a templated function.
template<T> T get( char const * name ) { ... }
//use
int a = obj.get<int>( "name" );
double b = obj.get<double>( "floaty" );
No, you can't do that.
Moreso, madness that way lies!

Clarification on Operators

I've been reading up on class operators and came across the following example:
class Array {
public:
int& operator[] (unsigned i) { if (i > 99) error(); return data[i]; }
private:
int data[100];
};
Does this mean I can replace [ and ] with whatever I want? For example, could I use parentheses?
Also, what is the significance of the ampersand in int& operator[]?
On a slightly less important note, would it be syntactically correct to use int& operator [] instead of int& operator[]?
Does this mean I can replace [ and ] with whatever I want?
Nopes! Not all operators can be overloaded.
For example, could I use parentheses?
You can but you shouldn't.
Also, what is the significance of the ampersand in int& operator[]?
It means you are returning a reference to an int variable.
EDIT: On a slightly less important note, would it be syntactically correct to use int& operator [] instead of int& operator[]?
There is no difference between the two.
What you are doing is defining an Array class that wrapes a simple integer array. By overloading the [] operator you can acces each element of the array as with any other array, the advantage here is that your are checking superior limit to avoid buffer overflow. The ampersand means that you are returning a reference to the array element, it allows you both assigment a value and getting a value. In c++ when you overload the [] operator dont forget both const and non-const versions:
int& operator[] (conts int a) {...}
int operator[] (conts int a) {...} const
You could use parentheses, because there also is an
operator()
and some libraries (eg. boost::blas) do this. BUT: You cannot make up new parenthesis, because there is no operator{} or operator<>
RE your syntax question: Haven't tried, but don't think so, because operator[] is the name of a function, and you shouldn't add whitespace to a function name.
While you can mostly define operators as you like, parens would be a problem. The reason is conflict with the classes constructor! Array(25), what does it mean? I'm not sure if this is allowed (though I'm quite sure someone else will know), but the point is that even if you are allowed you are going to have a problem with doing that.
In general - symbols that serve as operators can be overloaded/redefined You can specify how ==, &, > and [] work for your class. You can't decide the letter 'q' now means some type of comparison. As far as the () issue, im not sure.
The reference mark & is necessary for indexing because you want to potentially do assignment on the address returned, not just got a value. If you permit the lax description, the "majority' of your operators will not require this.
1) NO there is a fixed set of available 'overloadable' operators in C++.
See this table in wikipedia:
http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Table
There is an 'Overloadable' Column in each table
2) The int& indicates that you're returning a Reference to the value.
References in C++ are similar to pointers and worth their own discussion, but in the case of the operator here what it allows if for you to use this operator as the left hand operand of an assignment e.g.
x[3] = 0;
This wouldn't work if it just returned an int;