Related
Is it possible to overload [] operator twice? To allow, something like this: function[3][3](like in a two dimensional array).
If it is possible, I would like to see some example code.
You can overload operator[] to return an object on which you can use operator[] again to get a result.
class ArrayOfArrays {
public:
ArrayOfArrays() {
_arrayofarrays = new int*[10];
for(int i = 0; i < 10; ++i)
_arrayofarrays[i] = new int[10];
}
class Proxy {
public:
Proxy(int* _array) : _array(_array) { }
int operator[](int index) {
return _array[index];
}
private:
int* _array;
};
Proxy operator[](int index) {
return Proxy(_arrayofarrays[index]);
}
private:
int** _arrayofarrays;
};
Then you can use it like:
ArrayOfArrays aoa;
aoa[3][5];
This is just a simple example, you'd want to add a bunch of bounds checking and stuff, but you get the idea.
For a two dimensional array, specifically, you might get away with a single operator[] overload that returns a pointer to the first element of each row.
Then you can use the built-in indexing operator to access each element within the row.
An expression x[y][z] requires that x[y] evaluates to an object d that supports d[z].
This means that x[y] should be an object with an operator[] that evaluates to a "proxy object" that also supports an operator[].
This is the only way to chain them.
Alternatively, overload operator() to take multiple arguments, such that you might invoke myObject(x,y).
It is possible if you return some kind of proxy class in first [] call. However, there is other option: you can overload operator() that can accept any number of arguments (function(3,3)).
One approach is using std::pair<int,int>:
class Array2D
{
int** m_p2dArray;
public:
int operator[](const std::pair<int,int>& Index)
{
return m_p2dArray[Index.first][Index.second];
}
};
int main()
{
Array2D theArray;
pair<int, int> theIndex(2,3);
int nValue;
nValue = theArray[theIndex];
}
Of course, you may typedef the pair<int,int>
You can use a proxy object, something like this:
#include <iostream>
struct Object
{
struct Proxy
{
Object *mObj;
int mI;
Proxy(Object *obj, int i)
: mObj(obj), mI(i)
{
}
int operator[](int j)
{
return mI * j;
}
};
Proxy operator[](int i)
{
return Proxy(this, i);
}
};
int main()
{
Object o;
std::cout << o[2][3] << std::endl;
}
If, instead of saying a[x][y], you would like to say a[{x,y}], you can do like this:
struct Coordinate { int x, y; }
class Matrix {
int** data;
operator[](Coordinate c) {
return data[c.y][c.x];
}
}
It 'll be great if you can let me know what function, function[x] and function[x][y] are. But anyway let me consider it as an object declared somewhere like
SomeClass function;
(Because you said that it's operator overload, I think you won't be interested at array like SomeClass function[16][32];)
So function is an instance of type SomeClass. Then look up declaration of SomeClass for the return type of operator[] overload, just like
ReturnType operator[](ParamType);
Then function[x] will have the type ReturnType. Again look up ReturnType for the operator[] overload. If there is such a method, you could then use the expression function[x][y].
Note, unlike function(x, y), function[x][y] are 2 separate calls. So it's hard for compiler or runtime garantees the atomicity unless you use a lock in the context. A similar example is, libc says printf is atomic while successively calls to the overloaded operator<< in output stream are not. A statement like
std::cout << "hello" << std::endl;
might have problem in multi-thread application, but something like
printf("%s%s", "hello", "\n");
is fine.
template<class F>
struct indexer_t{
F f;
template<class I>
std::result_of_t<F const&(I)> operator[](I&&i)const{
return f(std::forward<I>(i))1;
}
};
template<class F>
indexer_t<std::decay_t<F>> as_indexer(F&& f){return {std::forward<F>(f)};}
This lets you take a lambda, and produce an indexer (with [] support).
Suppose you have an operator() that supports passing both coordinates at onxe as two arguments. Now writing [][] support is just:
auto operator[](size_t i){
return as_indexer(
[i,this](size_t j)->decltype(auto)
{return (*this)(i,j);}
);
}
auto operator[](size_t i)const{
return as_indexer(
[i,this](size_t j)->decltype(auto)
{return (*this)(i,j);}
);
}
And done. No custom class required.
#include<iostream>
using namespace std;
class Array
{
private: int *p;
public:
int length;
Array(int size = 0): length(size)
{
p=new int(length);
}
int& operator [](const int k)
{
return p[k];
}
};
class Matrix
{
private: Array *p;
public:
int r,c;
Matrix(int i=0, int j=0):r(i), c(j)
{
p= new Array[r];
}
Array& operator [](const int& i)
{
return p[i];
}
};
/*Driver program*/
int main()
{
Matrix M1(3,3); /*for checking purpose*/
M1[2][2]=5;
}
struct test
{
using array_reference = int(&)[32][32];
array_reference operator [] (std::size_t index)
{
return m_data[index];
}
private:
int m_data[32][32][32];
};
Found my own simple solution to this.
vector< vector< T > > or T** is required only when you have rows of variable length
and way too inefficient in terms of memory usage/allocations
if you require rectangular array consider doing some math instead!
see at() method:
template<typename T > class array2d {
protected:
std::vector< T > _dataStore;
size_t _sx;
public:
array2d(size_t sx, size_t sy = 1): _sx(sx), _dataStore(sx*sy) {}
T& at( size_t x, size_t y ) { return _dataStore[ x+y*sx]; }
const T& at( size_t x, size_t y ) const { return _dataStore[ x+y*sx]; }
const T& get( size_t x, size_t y ) const { return at(x,y); }
void set( size_t x, size_t y, const T& newValue ) { at(x,y) = newValue; }
};
The shortest and easiest solution:
class Matrix
{
public:
float m_matrix[4][4];
// for statements like matrix[0][0] = 1;
float* operator [] (int index)
{
return m_matrix[index];
}
// for statements like matrix[0][0] = otherMatrix[0][0];
const float* operator [] (int index) const
{
return m_matrix[index];
}
};
It is possible to overload multiple [] using a specialized template handler. Just to show how it works :
#include <iostream>
#include <algorithm>
#include <numeric>
#include <tuple>
#include <array>
using namespace std;
// the number '3' is the number of [] to overload (fixed at compile time)
struct TestClass : public SubscriptHandler<TestClass,int,int,3> {
// the arguments will be packed in reverse order into a std::array of size 3
// and the last [] will forward them to callSubscript()
int callSubscript(array<int,3>& v) {
return accumulate(v.begin(),v.end(),0);
}
};
int main() {
TestClass a;
cout<<a[3][2][9]; // prints 14 (3+2+9)
return 0;
}
And now the definition of SubscriptHandler<ClassType,ArgType,RetType,N> to make the previous code work. It only shows how it can be done. This solution is optimal nor bug-free (not threadsafe for instance).
#include <iostream>
#include <algorithm>
#include <numeric>
#include <tuple>
#include <array>
using namespace std;
template <typename ClassType,typename ArgType,typename RetType, int N> class SubscriptHandler;
template<typename ClassType,typename ArgType,typename RetType, int N,int Recursion> class SubscriptHandler_ {
ClassType*obj;
array<ArgType,N+1> *arr;
typedef SubscriptHandler_<ClassType,ArgType,RetType,N,Recursion-1> Subtype;
friend class SubscriptHandler_<ClassType,ArgType,RetType,N,Recursion+1>;
friend class SubscriptHandler<ClassType,ArgType,RetType,N+1>;
public:
Subtype operator[](const ArgType& arg){
Subtype s;
s.obj = obj;
s.arr = arr;
arr->at(Recursion)=arg;
return s;
}
};
template<typename ClassType,typename ArgType,typename RetType,int N> class SubscriptHandler_<ClassType,ArgType,RetType,N,0> {
ClassType*obj;
array<ArgType,N+1> *arr;
friend class SubscriptHandler_<ClassType,ArgType,RetType,N,1>;
friend class SubscriptHandler<ClassType,ArgType,RetType,N+1>;
public:
RetType operator[](const ArgType& arg){
arr->at(0) = arg;
return obj->callSubscript(*arr);
}
};
template<typename ClassType,typename ArgType,typename RetType, int N> class SubscriptHandler{
array<ArgType,N> arr;
ClassType*ptr;
typedef SubscriptHandler_<ClassType,ArgType,RetType,N-1,N-2> Subtype;
protected:
SubscriptHandler() {
ptr=(ClassType*)this;
}
public:
Subtype operator[](const ArgType& arg){
Subtype s;
s.arr=&arr;
s.obj=ptr;
s.arr->at(N-1)=arg;
return s;
}
};
template<typename ClassType,typename ArgType,typename RetType> struct SubscriptHandler<ClassType,ArgType,RetType,1>{
RetType operator[](const ArgType&arg) {
array<ArgType,1> arr;
arr.at(0)=arg;
return ((ClassType*)this)->callSubscript(arr);
}
};
With a std::vector<std::vector<type*>>, you can build the inside vector using custom input operator that iterate over your data and return a pointer to each data.
For example:
size_t w, h;
int* myData = retrieveData(&w, &h);
std::vector<std::vector<int*> > data;
data.reserve(w);
template<typename T>
struct myIterator : public std::iterator<std::input_iterator_tag, T*>
{
myIterator(T* data) :
_data(data)
{}
T* _data;
bool operator==(const myIterator& rhs){return rhs.data == data;}
bool operator!=(const myIterator& rhs){return rhs.data != data;}
T* operator*(){return data;}
T* operator->(){return data;}
myIterator& operator++(){data = &data[1]; return *this; }
};
for (size_t i = 0; i < w; ++i)
{
data.push_back(std::vector<int*>(myIterator<int>(&myData[i * h]),
myIterator<int>(&myData[(i + 1) * h])));
}
Live example
This solution has the advantage of providing you with a real STL container, so you can use special for loops, STL algorithms, and so on.
for (size_t i = 0; i < w; ++i)
for (size_t j = 0; j < h; ++j)
std::cout << *data[i][j] << std::endl;
However, it does create vectors of pointers, so if you're using small datastructures such as this one you can directly copy the content inside the array.
Sample code:
template<class T>
class Array2D
{
public:
Array2D(int a, int b)
{
num1 = (T**)new int [a*sizeof(int*)];
for(int i = 0; i < a; i++)
num1[i] = new int [b*sizeof(int)];
for (int i = 0; i < a; i++) {
for (int j = 0; j < b; j++) {
num1[i][j] = i*j;
}
}
}
class Array1D
{
public:
Array1D(int* a):temp(a) {}
T& operator[](int a)
{
return temp[a];
}
T* temp;
};
T** num1;
Array1D operator[] (int a)
{
return Array1D(num1[a]);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Array2D<int> arr(20, 30);
std::cout << arr[2][3];
getchar();
return 0;
}
Using C++11 and the Standard Library you can make a very nice two-dimensional array in a single line of code:
std::array<std::array<int, columnCount>, rowCount> myMatrix {0};
std::array<std::array<std::string, columnCount>, rowCount> myStringMatrix;
std::array<std::array<Widget, columnCount>, rowCount> myWidgetMatrix;
By deciding the inner matrix represents rows, you access the matrix with an myMatrix[y][x] syntax:
myMatrix[0][0] = 1;
myMatrix[0][3] = 2;
myMatrix[3][4] = 3;
std::cout << myMatrix[3][4]; // outputs 3
myStringMatrix[2][4] = "foo";
myWidgetMatrix[1][5].doTheStuff();
And you can use ranged-for for output:
for (const auto &row : myMatrix) {
for (const auto &elem : row) {
std::cout << elem << " ";
}
std::cout << std::endl;
}
(Deciding the inner array represents columns would allow for an foo[x][y] syntax but you'd need to use clumsier for(;;) loops to display output.)
I know that for a simple 2d matrix like:
class Matrix{
vector<vector<int>> data;
};
In order to support operation like Matrix[][], you just need to overload operator[] which returns the corresponding row vector like:
vector<int>& operator[](int row){return data[row]};
My question is how to implement the subscript operator if I need to perform some transformation on the col.
Say for i th row, the size of that row is 10.
I want to return the actual data when j is less than 5 but some other value say i+j when j is greater than 5.
Is there a way to achieve this? Thanks!
You might return proxy, something like:
class Proxy {
public:
Proxy(std::vector<std::vector<int>>* data, std::size_t i) : data(data), i(i) {}
int& operator[](std::size_t j) {
if (j < 5) { return (*data)[i][j]; }
else { return i + j; }
}
private:
std::vector<std::vector<int>>* data;
std::size_t i;
};
class Matrix{
public:
Proxy operator[](std::size_t i) { return {&data, i}; }
private:
std::vector<std::vector<int>> data;
};
I'm porting code that uses a very large array of floats, which may trigger malloc failures from c to c++. I asked a question about whether I should use vectors or deques and Niki Yoshiuchi generously offered me this example of a safely wrapped type:
template<typename T>
class VectorDeque
{
private:
enum TYPE { NONE, DEQUE, VECTOR };
std::deque<T> m_d;
std::vector<T> m_v;
TYPE m_type;
...
public:
void resize(size_t n)
{
switch(m_type)
{
case NONE:
try
{
m_v.resize(n);
m_type = VECTOR;
}
catch(std::bad_alloc &ba)
{
m_d.resize(n);
m_type = DEQUE;
}
break;
}
}
};
I needed a 2D vector of vectors/deque of deques, so I modified it to the following code:
template<typename T>
class VectorDeque
{
private:
enum STORAGE_CONTAINER { NONE, DEQUE, VECTOR };
std::deque<std::deque<T> > x_d,y_d,z_d;
std::vector<std::vector<T> > x_v,y_v,z_v;
TYPE my_container;
public:
void resize(size_t num_atoms, size_t num_frames)
{
switch(m_type)
{
case NONE:
try
{
x_v.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
x_v[counter].resize(num_frames);
y_v.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
y_v[counter].resize(num_frames);
z_v.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
z_v[counter].resize(num_frames);
my_container = VECTOR;
}
catch(std::bad_alloc &e)
{
x_d.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
x_d[counter].resize(num_frames);
y_d.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
y_d[counter].resize(num_frames);
z_d.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
z_d[counter].resize(num_frames);
my_container = DEQUE;
}
break;
}
}
};
I now want to be able to define my bracket operators so that I can have a statement like
x[1][2] directly access whichever is the real memory container I'm using (given by the value of my enumerated variable.
I've seen a couple of tutorials floating around about overriding the brackets operator, but have positively no idea to override double brackets.
How can you overload double brackets?
Additionally, how would you overload double iterators (in case I want to use an iterator, as opposed to direct indexing)?
EDIT 1:
Based on the solution from Martin York/Matteo Italia I devised the following class:
template<typename T>
class VectorDeque2D
{
public:
class VectorDeque2D_Inner_Set
{
VectorDeque2D& parent;
int first_index;
public:
// Just init the temp object
VectorDeque2D_Inner_Set(My2D& p, int first_Index) :
parent(p),
first_Index(first_index) {}
// Here we get the value.
T& operator[](int second_index) const
{ return parent.get(first_index,second_index);}
};
// Return an object that defines its own operator[] that will access the data.
// The temp object is very trivial and just allows access to the data via
// operator[]
VectorDeque2D_Inner_Set operator[](unsigned int first_index) {
return (*this, x);
}
void resize_first_index(unsigned int first_index) {
try {
my_vector.resize(first_index);
my_container = VECTOR;
}
catch(std::bad_alloc &e) {
my_deque.resize(first_index);
my_container = DEQUE;
}
}
void resize_second_index(unsigned int second_index) {
try {
for (unsigned int couter=0;couter < my_vector.size(); counter++) {
my_vector[counter].resize(second_index);
}
my_container = VECTOR;
}
catch(std::bad_alloc &e) {
for (unsigned int couter=0;couter < my_deque.size(); counter++) {
my_deque[counter].resize(second_index);
}
my_container = DEQUE;
}
}
void resize(unsigned int first_index,
unsigned int second_index) {
try {
my_vector.resize(first_index);
for (unsigned int couter=0;couter < my_vector.size(); counter++) {
my_vector[counter].resize(second_index);
}
my_container = VECTOR;
}
catch(std::bad_alloc &e) {
my_deque.resize(first_index);
for (unsigned int couter=0;couter < my_deque.size(); counter++) {
my_deque[counter].resize(second_index);
}
my_container = DEQUE;
}
}
private:
enum STORAGE_CONTAINER { NONE, DEQUE, VECTOR };
friend class VectorDeque2D_Inner_Set;
std::vector<std::vector<T> > my_vector;
std::deque<std::deque<T> > my_deque;
STORAGE_CONTAINER my_container;
T& get(int x,int y) {
T temp_val;
if(my_container == VECTOR) {
temp_val = my_vector[first_index][second_index];
}
else if(my_container == DEQUE) {
temp_val = my_deque[first_index][second_index];
}
return temp_val;
}
};
Finally a size-safe 2D container!! Thanks guys!
There are two main techniques:
1) Use operator() rather than operator[].
This is because the operator() allows multiple parameters.
class My2D
{
public:
int& operator()(int x,int y) { return pget(x,y);}
private:
int& pget(int x,int y) { /* retrieve data from 2D storage */ }
};
2) Use operator[] but return an intermediate object.
You can then apply the second operator[] to the intermediate object.
class My2D
{
public:
class My2DRow
{
My2D& parent;
int x;
public:
My2DRow(My2D& p, int theX) : parent(p), x(theX) {} // Just init the temp object
int& operator[](int y) const { return parent.pget(x,y);} // Here we get the value.
};
// Return an object that defines its own operator[] that will access the data.
// The temp object is very trivial and just allows access to the data via operator[]
My2DRow operator[](int x) { return My2DRow(*this, x);}
private:
friend class My2DRow;
int& pget(int x,int y) { /* retrieve data from 2D storage */ }
};
int main()
{
My2D data;
int& val = data[1][2]; // works fine.
// This is the same as
My2D::My2DRow row = data[1];
int& val2 = row[2];
}
I prefer the second technique.
This is because it leaves the original code untouched and more natural to read (in an array context). Of course you pay for the simplicity at the high level with slightly more complex code implementing your 2D array.
How can you overload double brackets?
I didn't fully understand your question, but you have to overload brackets, and make them return an object who overloads its own bracket operator.
For example, if you have a vector of vectors, the work is already done: vector < vector < something > > overloads operator[], which returns a vector< something >; this, in turn, has its bracket operator overloaded (and it returns a something object), so you can simply do:
vector<vector<something> > vec;
// ...
something s = vec[2][3];
Example with a proxy object:
template <typename T>
class Container
{
private:
// ...
public:
// Proxy object used to provide the second brackets
template <typename T>
class OperatorBracketHelper
{
Container<T> & parent;
size_t firstIndex;
public:
OperatorBracketHelper(Container<T> & Parent, size_t FirstIndex) : parent(Parent), firstIndex(FirstIndex) {}
// This is the method called for the "second brackets"
T & operator[](size_t SecondIndex)
{
// Call the parent GetElement method which will actually retrieve the element
return parent.GetElement(firstIndex, SecondIndex);
}
}
// This is the method called for the "first brackets"
OperatorBracketHelper<T> operator[](size_t FirstIndex)
{
// Return a proxy object that "knows" to which container it has to ask the element
// and which is the first index (specified in this call)
return OperatorBracketHelper<T>(*this, FirstIndex);
}
T & GetElement(size_t FirstIndex, size_t SecondIndex)
{
// Here the actual element retrieval is done
// ...
}
}
(add overloaded const methods wherever appropriate :) )
Note that with this method you lose almost nothing in respect to an operator() implementation, since the retrieval is still done in one single place, without constraints on the usage of the two indexes, having both indexes at the moment of performing the retrieval, and without returning "fat" temporary objects (OperatorBracketHelper is just as big as two pointers, and can be easily optimized away by the compiler).
There is no "double brackets" operator in C++. What you need to do is define a single [] operator and have it return a reference to another object, which can in turn respond to its own [] operator. This can be nested as many levels deep as you require.
For example, when you create a vector of vectors, the [] operator on the outer vector returns a reference to one of the inner vectors; the [] operator on that vector returns a reference to an individual element of the vector.
std::vector<std::vector<float> > example;
std::vector<float> & first = example[0]; // the first level returns a reference to a vector
float & second = example[0][0]; // the same as first[0]
Don't overload the [] operator, overload the () operator.
See this link:Overloading Subscript Operator.
I highly suggest reading through the C++ FAQ Lite at least once before posting to Stack Overflow. Also, searching Stack Overflow may yield some useful information also.
I covered overloading operator[] for a multi-dimensional array in an answer to a previous question.
I'd probably deal with iterators pretty similarly: Have one iterator that represents a "slice" (row or column) of the multi-dimensional array, and then another that represents an element in that slice.
Is it possible to overload [] operator twice? To allow, something like this: function[3][3](like in a two dimensional array).
If it is possible, I would like to see some example code.
You can overload operator[] to return an object on which you can use operator[] again to get a result.
class ArrayOfArrays {
public:
ArrayOfArrays() {
_arrayofarrays = new int*[10];
for(int i = 0; i < 10; ++i)
_arrayofarrays[i] = new int[10];
}
class Proxy {
public:
Proxy(int* _array) : _array(_array) { }
int operator[](int index) {
return _array[index];
}
private:
int* _array;
};
Proxy operator[](int index) {
return Proxy(_arrayofarrays[index]);
}
private:
int** _arrayofarrays;
};
Then you can use it like:
ArrayOfArrays aoa;
aoa[3][5];
This is just a simple example, you'd want to add a bunch of bounds checking and stuff, but you get the idea.
For a two dimensional array, specifically, you might get away with a single operator[] overload that returns a pointer to the first element of each row.
Then you can use the built-in indexing operator to access each element within the row.
An expression x[y][z] requires that x[y] evaluates to an object d that supports d[z].
This means that x[y] should be an object with an operator[] that evaluates to a "proxy object" that also supports an operator[].
This is the only way to chain them.
Alternatively, overload operator() to take multiple arguments, such that you might invoke myObject(x,y).
It is possible if you return some kind of proxy class in first [] call. However, there is other option: you can overload operator() that can accept any number of arguments (function(3,3)).
One approach is using std::pair<int,int>:
class Array2D
{
int** m_p2dArray;
public:
int operator[](const std::pair<int,int>& Index)
{
return m_p2dArray[Index.first][Index.second];
}
};
int main()
{
Array2D theArray;
pair<int, int> theIndex(2,3);
int nValue;
nValue = theArray[theIndex];
}
Of course, you may typedef the pair<int,int>
You can use a proxy object, something like this:
#include <iostream>
struct Object
{
struct Proxy
{
Object *mObj;
int mI;
Proxy(Object *obj, int i)
: mObj(obj), mI(i)
{
}
int operator[](int j)
{
return mI * j;
}
};
Proxy operator[](int i)
{
return Proxy(this, i);
}
};
int main()
{
Object o;
std::cout << o[2][3] << std::endl;
}
If, instead of saying a[x][y], you would like to say a[{x,y}], you can do like this:
struct Coordinate { int x, y; }
class Matrix {
int** data;
operator[](Coordinate c) {
return data[c.y][c.x];
}
}
It 'll be great if you can let me know what function, function[x] and function[x][y] are. But anyway let me consider it as an object declared somewhere like
SomeClass function;
(Because you said that it's operator overload, I think you won't be interested at array like SomeClass function[16][32];)
So function is an instance of type SomeClass. Then look up declaration of SomeClass for the return type of operator[] overload, just like
ReturnType operator[](ParamType);
Then function[x] will have the type ReturnType. Again look up ReturnType for the operator[] overload. If there is such a method, you could then use the expression function[x][y].
Note, unlike function(x, y), function[x][y] are 2 separate calls. So it's hard for compiler or runtime garantees the atomicity unless you use a lock in the context. A similar example is, libc says printf is atomic while successively calls to the overloaded operator<< in output stream are not. A statement like
std::cout << "hello" << std::endl;
might have problem in multi-thread application, but something like
printf("%s%s", "hello", "\n");
is fine.
template<class F>
struct indexer_t{
F f;
template<class I>
std::result_of_t<F const&(I)> operator[](I&&i)const{
return f(std::forward<I>(i))1;
}
};
template<class F>
indexer_t<std::decay_t<F>> as_indexer(F&& f){return {std::forward<F>(f)};}
This lets you take a lambda, and produce an indexer (with [] support).
Suppose you have an operator() that supports passing both coordinates at onxe as two arguments. Now writing [][] support is just:
auto operator[](size_t i){
return as_indexer(
[i,this](size_t j)->decltype(auto)
{return (*this)(i,j);}
);
}
auto operator[](size_t i)const{
return as_indexer(
[i,this](size_t j)->decltype(auto)
{return (*this)(i,j);}
);
}
And done. No custom class required.
#include<iostream>
using namespace std;
class Array
{
private: int *p;
public:
int length;
Array(int size = 0): length(size)
{
p=new int(length);
}
int& operator [](const int k)
{
return p[k];
}
};
class Matrix
{
private: Array *p;
public:
int r,c;
Matrix(int i=0, int j=0):r(i), c(j)
{
p= new Array[r];
}
Array& operator [](const int& i)
{
return p[i];
}
};
/*Driver program*/
int main()
{
Matrix M1(3,3); /*for checking purpose*/
M1[2][2]=5;
}
struct test
{
using array_reference = int(&)[32][32];
array_reference operator [] (std::size_t index)
{
return m_data[index];
}
private:
int m_data[32][32][32];
};
Found my own simple solution to this.
vector< vector< T > > or T** is required only when you have rows of variable length
and way too inefficient in terms of memory usage/allocations
if you require rectangular array consider doing some math instead!
see at() method:
template<typename T > class array2d {
protected:
std::vector< T > _dataStore;
size_t _sx;
public:
array2d(size_t sx, size_t sy = 1): _sx(sx), _dataStore(sx*sy) {}
T& at( size_t x, size_t y ) { return _dataStore[ x+y*sx]; }
const T& at( size_t x, size_t y ) const { return _dataStore[ x+y*sx]; }
const T& get( size_t x, size_t y ) const { return at(x,y); }
void set( size_t x, size_t y, const T& newValue ) { at(x,y) = newValue; }
};
The shortest and easiest solution:
class Matrix
{
public:
float m_matrix[4][4];
// for statements like matrix[0][0] = 1;
float* operator [] (int index)
{
return m_matrix[index];
}
// for statements like matrix[0][0] = otherMatrix[0][0];
const float* operator [] (int index) const
{
return m_matrix[index];
}
};
It is possible to overload multiple [] using a specialized template handler. Just to show how it works :
#include <iostream>
#include <algorithm>
#include <numeric>
#include <tuple>
#include <array>
using namespace std;
// the number '3' is the number of [] to overload (fixed at compile time)
struct TestClass : public SubscriptHandler<TestClass,int,int,3> {
// the arguments will be packed in reverse order into a std::array of size 3
// and the last [] will forward them to callSubscript()
int callSubscript(array<int,3>& v) {
return accumulate(v.begin(),v.end(),0);
}
};
int main() {
TestClass a;
cout<<a[3][2][9]; // prints 14 (3+2+9)
return 0;
}
And now the definition of SubscriptHandler<ClassType,ArgType,RetType,N> to make the previous code work. It only shows how it can be done. This solution is optimal nor bug-free (not threadsafe for instance).
#include <iostream>
#include <algorithm>
#include <numeric>
#include <tuple>
#include <array>
using namespace std;
template <typename ClassType,typename ArgType,typename RetType, int N> class SubscriptHandler;
template<typename ClassType,typename ArgType,typename RetType, int N,int Recursion> class SubscriptHandler_ {
ClassType*obj;
array<ArgType,N+1> *arr;
typedef SubscriptHandler_<ClassType,ArgType,RetType,N,Recursion-1> Subtype;
friend class SubscriptHandler_<ClassType,ArgType,RetType,N,Recursion+1>;
friend class SubscriptHandler<ClassType,ArgType,RetType,N+1>;
public:
Subtype operator[](const ArgType& arg){
Subtype s;
s.obj = obj;
s.arr = arr;
arr->at(Recursion)=arg;
return s;
}
};
template<typename ClassType,typename ArgType,typename RetType,int N> class SubscriptHandler_<ClassType,ArgType,RetType,N,0> {
ClassType*obj;
array<ArgType,N+1> *arr;
friend class SubscriptHandler_<ClassType,ArgType,RetType,N,1>;
friend class SubscriptHandler<ClassType,ArgType,RetType,N+1>;
public:
RetType operator[](const ArgType& arg){
arr->at(0) = arg;
return obj->callSubscript(*arr);
}
};
template<typename ClassType,typename ArgType,typename RetType, int N> class SubscriptHandler{
array<ArgType,N> arr;
ClassType*ptr;
typedef SubscriptHandler_<ClassType,ArgType,RetType,N-1,N-2> Subtype;
protected:
SubscriptHandler() {
ptr=(ClassType*)this;
}
public:
Subtype operator[](const ArgType& arg){
Subtype s;
s.arr=&arr;
s.obj=ptr;
s.arr->at(N-1)=arg;
return s;
}
};
template<typename ClassType,typename ArgType,typename RetType> struct SubscriptHandler<ClassType,ArgType,RetType,1>{
RetType operator[](const ArgType&arg) {
array<ArgType,1> arr;
arr.at(0)=arg;
return ((ClassType*)this)->callSubscript(arr);
}
};
With a std::vector<std::vector<type*>>, you can build the inside vector using custom input operator that iterate over your data and return a pointer to each data.
For example:
size_t w, h;
int* myData = retrieveData(&w, &h);
std::vector<std::vector<int*> > data;
data.reserve(w);
template<typename T>
struct myIterator : public std::iterator<std::input_iterator_tag, T*>
{
myIterator(T* data) :
_data(data)
{}
T* _data;
bool operator==(const myIterator& rhs){return rhs.data == data;}
bool operator!=(const myIterator& rhs){return rhs.data != data;}
T* operator*(){return data;}
T* operator->(){return data;}
myIterator& operator++(){data = &data[1]; return *this; }
};
for (size_t i = 0; i < w; ++i)
{
data.push_back(std::vector<int*>(myIterator<int>(&myData[i * h]),
myIterator<int>(&myData[(i + 1) * h])));
}
Live example
This solution has the advantage of providing you with a real STL container, so you can use special for loops, STL algorithms, and so on.
for (size_t i = 0; i < w; ++i)
for (size_t j = 0; j < h; ++j)
std::cout << *data[i][j] << std::endl;
However, it does create vectors of pointers, so if you're using small datastructures such as this one you can directly copy the content inside the array.
Sample code:
template<class T>
class Array2D
{
public:
Array2D(int a, int b)
{
num1 = (T**)new int [a*sizeof(int*)];
for(int i = 0; i < a; i++)
num1[i] = new int [b*sizeof(int)];
for (int i = 0; i < a; i++) {
for (int j = 0; j < b; j++) {
num1[i][j] = i*j;
}
}
}
class Array1D
{
public:
Array1D(int* a):temp(a) {}
T& operator[](int a)
{
return temp[a];
}
T* temp;
};
T** num1;
Array1D operator[] (int a)
{
return Array1D(num1[a]);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Array2D<int> arr(20, 30);
std::cout << arr[2][3];
getchar();
return 0;
}
Using C++11 and the Standard Library you can make a very nice two-dimensional array in a single line of code:
std::array<std::array<int, columnCount>, rowCount> myMatrix {0};
std::array<std::array<std::string, columnCount>, rowCount> myStringMatrix;
std::array<std::array<Widget, columnCount>, rowCount> myWidgetMatrix;
By deciding the inner matrix represents rows, you access the matrix with an myMatrix[y][x] syntax:
myMatrix[0][0] = 1;
myMatrix[0][3] = 2;
myMatrix[3][4] = 3;
std::cout << myMatrix[3][4]; // outputs 3
myStringMatrix[2][4] = "foo";
myWidgetMatrix[1][5].doTheStuff();
And you can use ranged-for for output:
for (const auto &row : myMatrix) {
for (const auto &elem : row) {
std::cout << elem << " ";
}
std::cout << std::endl;
}
(Deciding the inner array represents columns would allow for an foo[x][y] syntax but you'd need to use clumsier for(;;) loops to display output.)
I'm porting code that uses a very large array of floats, which may trigger malloc failures from c to c++. I asked a question about whether I should use vectors or deques and Niki Yoshiuchi generously offered me this example of a safely wrapped type:
template<typename T>
class VectorDeque
{
private:
enum TYPE { NONE, DEQUE, VECTOR };
std::deque<T> m_d;
std::vector<T> m_v;
TYPE m_type;
...
public:
void resize(size_t n)
{
switch(m_type)
{
case NONE:
try
{
m_v.resize(n);
m_type = VECTOR;
}
catch(std::bad_alloc &ba)
{
m_d.resize(n);
m_type = DEQUE;
}
break;
}
}
};
I needed a 2D vector of vectors/deque of deques, so I modified it to the following code:
template<typename T>
class VectorDeque
{
private:
enum STORAGE_CONTAINER { NONE, DEQUE, VECTOR };
std::deque<std::deque<T> > x_d,y_d,z_d;
std::vector<std::vector<T> > x_v,y_v,z_v;
TYPE my_container;
public:
void resize(size_t num_atoms, size_t num_frames)
{
switch(m_type)
{
case NONE:
try
{
x_v.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
x_v[counter].resize(num_frames);
y_v.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
y_v[counter].resize(num_frames);
z_v.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
z_v[counter].resize(num_frames);
my_container = VECTOR;
}
catch(std::bad_alloc &e)
{
x_d.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
x_d[counter].resize(num_frames);
y_d.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
y_d[counter].resize(num_frames);
z_d.resize(num_atoms);
for (unsigned int couter=0;couter < num_frames; counter++)
z_d[counter].resize(num_frames);
my_container = DEQUE;
}
break;
}
}
};
I now want to be able to define my bracket operators so that I can have a statement like
x[1][2] directly access whichever is the real memory container I'm using (given by the value of my enumerated variable.
I've seen a couple of tutorials floating around about overriding the brackets operator, but have positively no idea to override double brackets.
How can you overload double brackets?
Additionally, how would you overload double iterators (in case I want to use an iterator, as opposed to direct indexing)?
EDIT 1:
Based on the solution from Martin York/Matteo Italia I devised the following class:
template<typename T>
class VectorDeque2D
{
public:
class VectorDeque2D_Inner_Set
{
VectorDeque2D& parent;
int first_index;
public:
// Just init the temp object
VectorDeque2D_Inner_Set(My2D& p, int first_Index) :
parent(p),
first_Index(first_index) {}
// Here we get the value.
T& operator[](int second_index) const
{ return parent.get(first_index,second_index);}
};
// Return an object that defines its own operator[] that will access the data.
// The temp object is very trivial and just allows access to the data via
// operator[]
VectorDeque2D_Inner_Set operator[](unsigned int first_index) {
return (*this, x);
}
void resize_first_index(unsigned int first_index) {
try {
my_vector.resize(first_index);
my_container = VECTOR;
}
catch(std::bad_alloc &e) {
my_deque.resize(first_index);
my_container = DEQUE;
}
}
void resize_second_index(unsigned int second_index) {
try {
for (unsigned int couter=0;couter < my_vector.size(); counter++) {
my_vector[counter].resize(second_index);
}
my_container = VECTOR;
}
catch(std::bad_alloc &e) {
for (unsigned int couter=0;couter < my_deque.size(); counter++) {
my_deque[counter].resize(second_index);
}
my_container = DEQUE;
}
}
void resize(unsigned int first_index,
unsigned int second_index) {
try {
my_vector.resize(first_index);
for (unsigned int couter=0;couter < my_vector.size(); counter++) {
my_vector[counter].resize(second_index);
}
my_container = VECTOR;
}
catch(std::bad_alloc &e) {
my_deque.resize(first_index);
for (unsigned int couter=0;couter < my_deque.size(); counter++) {
my_deque[counter].resize(second_index);
}
my_container = DEQUE;
}
}
private:
enum STORAGE_CONTAINER { NONE, DEQUE, VECTOR };
friend class VectorDeque2D_Inner_Set;
std::vector<std::vector<T> > my_vector;
std::deque<std::deque<T> > my_deque;
STORAGE_CONTAINER my_container;
T& get(int x,int y) {
T temp_val;
if(my_container == VECTOR) {
temp_val = my_vector[first_index][second_index];
}
else if(my_container == DEQUE) {
temp_val = my_deque[first_index][second_index];
}
return temp_val;
}
};
Finally a size-safe 2D container!! Thanks guys!
There are two main techniques:
1) Use operator() rather than operator[].
This is because the operator() allows multiple parameters.
class My2D
{
public:
int& operator()(int x,int y) { return pget(x,y);}
private:
int& pget(int x,int y) { /* retrieve data from 2D storage */ }
};
2) Use operator[] but return an intermediate object.
You can then apply the second operator[] to the intermediate object.
class My2D
{
public:
class My2DRow
{
My2D& parent;
int x;
public:
My2DRow(My2D& p, int theX) : parent(p), x(theX) {} // Just init the temp object
int& operator[](int y) const { return parent.pget(x,y);} // Here we get the value.
};
// Return an object that defines its own operator[] that will access the data.
// The temp object is very trivial and just allows access to the data via operator[]
My2DRow operator[](int x) { return My2DRow(*this, x);}
private:
friend class My2DRow;
int& pget(int x,int y) { /* retrieve data from 2D storage */ }
};
int main()
{
My2D data;
int& val = data[1][2]; // works fine.
// This is the same as
My2D::My2DRow row = data[1];
int& val2 = row[2];
}
I prefer the second technique.
This is because it leaves the original code untouched and more natural to read (in an array context). Of course you pay for the simplicity at the high level with slightly more complex code implementing your 2D array.
How can you overload double brackets?
I didn't fully understand your question, but you have to overload brackets, and make them return an object who overloads its own bracket operator.
For example, if you have a vector of vectors, the work is already done: vector < vector < something > > overloads operator[], which returns a vector< something >; this, in turn, has its bracket operator overloaded (and it returns a something object), so you can simply do:
vector<vector<something> > vec;
// ...
something s = vec[2][3];
Example with a proxy object:
template <typename T>
class Container
{
private:
// ...
public:
// Proxy object used to provide the second brackets
template <typename T>
class OperatorBracketHelper
{
Container<T> & parent;
size_t firstIndex;
public:
OperatorBracketHelper(Container<T> & Parent, size_t FirstIndex) : parent(Parent), firstIndex(FirstIndex) {}
// This is the method called for the "second brackets"
T & operator[](size_t SecondIndex)
{
// Call the parent GetElement method which will actually retrieve the element
return parent.GetElement(firstIndex, SecondIndex);
}
}
// This is the method called for the "first brackets"
OperatorBracketHelper<T> operator[](size_t FirstIndex)
{
// Return a proxy object that "knows" to which container it has to ask the element
// and which is the first index (specified in this call)
return OperatorBracketHelper<T>(*this, FirstIndex);
}
T & GetElement(size_t FirstIndex, size_t SecondIndex)
{
// Here the actual element retrieval is done
// ...
}
}
(add overloaded const methods wherever appropriate :) )
Note that with this method you lose almost nothing in respect to an operator() implementation, since the retrieval is still done in one single place, without constraints on the usage of the two indexes, having both indexes at the moment of performing the retrieval, and without returning "fat" temporary objects (OperatorBracketHelper is just as big as two pointers, and can be easily optimized away by the compiler).
There is no "double brackets" operator in C++. What you need to do is define a single [] operator and have it return a reference to another object, which can in turn respond to its own [] operator. This can be nested as many levels deep as you require.
For example, when you create a vector of vectors, the [] operator on the outer vector returns a reference to one of the inner vectors; the [] operator on that vector returns a reference to an individual element of the vector.
std::vector<std::vector<float> > example;
std::vector<float> & first = example[0]; // the first level returns a reference to a vector
float & second = example[0][0]; // the same as first[0]
Don't overload the [] operator, overload the () operator.
See this link:Overloading Subscript Operator.
I highly suggest reading through the C++ FAQ Lite at least once before posting to Stack Overflow. Also, searching Stack Overflow may yield some useful information also.
I covered overloading operator[] for a multi-dimensional array in an answer to a previous question.
I'd probably deal with iterators pretty similarly: Have one iterator that represents a "slice" (row or column) of the multi-dimensional array, and then another that represents an element in that slice.