C++ [] array operator with multiple arguments?

C++ArraysOperatorsOperator Keyword

C++ Problem Overview


Can I define in C++ an array operator that takes multiple arguments? I tried it like this:

const T& operator[](const int i, const int j, const int k) const{ 
	return m_cells[k*m_resSqr+j*m_res+i];
}

T& operator[](const int i, const int j, const int k){ 
	return m_cells[k*m_resSqr+j*m_res+i];		
}

But I'm getting this error:

error C2804 binary operator '[' has too many parameters

C++ Solutions


Solution 1 - C++

Prior to C++23, you could not overload operator[] to accept multiple arguments. As a workaround, you instead can overload operator(). (See How do I create a subscript operator for a Matrix class? from the C++ FAQ.)


From C++23, as mentioned in a (deleted) answer by cigien, multiple subscript arguments can be passed to operator[] directly. See this demo from the cppreference page.

Solution 2 - C++

It is not possible to overload the [] operator to accept multiple arguments, but an alternative is to use the proxy pattern.

In two words: a[x][y], the first expression (a[x]) would return a different type, named proxy type, which would have another operator[]. It would call something like _storedReferenceToOriginalObject->At(x,y) of the original class.

You will not be able to do a[x,y], but I guess you wanted to overload the usual C++-style 2D array syntax anyway.

Solution 3 - C++

There's a nice little trick you can do with the uniform initialization syntax available in C++11. Instead of taking the index directly, you take a POD.

struct indices
{
  std::size_t i, j, k;
};

T& operator[](indices idx)
{
  return m_cells[idx.k * m_resSqr + idx.j * m_res + idx.i];
}

And then use the new syntax:

my_array<int> arr;
// ...
arr[{1, 2, 3}] = 42;

Solution 4 - C++

For completeness sake: There is a way to actually use the bracket operator with multiple arguments, if they are not basic data types, namely by overloading the comma operator and not the bracket operator, see the following post about comma overloading:

https://stackoverflow.com/a/18136340/5836981

Disclaimer: in my opinion overloading the comma operator is error prone and renders code more obscure, and is worth considering only in more exotic cases. I added this answer because I came over an instance of this in some code and it took me a while to figure out that the key was not the [] operator (which cannot be overloaded with multiple arguments) but the ,operator.

Solution 5 - C++

Edit: as pointed in comment, in C++20 operator comma will be deprecated, so as the answer below.

You can't overload operator[], but you can fake it by overloading operator, instead.

Following your code it becomes:

T& operator,(const int i, const int j, const int k){ 
    return m_cells[k*m_resSqr+j*m_res+i];       
}

now you'll be able to call

something[1, 2, 3]

You can extend it using templates, templates with variadic arguments, std::pair or std::tuple depending on your use case and C++ version

Solution 6 - C++

N-dimensional arrays of arbitrary type and size in C++:

This answer is inspired by the answer of Pavel Radzivilovsky, thanks for that. I had a bit of a hard time realizing the implementation, as it was my first stab at recursive templates. I'd like to share what I have done such that others can understand more quickly than I did.

I have written a c++ template class to create a n-dimensional array of arbitrary type and size. It needs to be instantiated with the array type and the number of dimensions. The size can be changed dynamically. I've given below a bare (stripped) working version of how to create a multidimensional array of which the elements can be accessed through successive application of the operator[] (e.g. array[x][y][z]). This version can only handle arrays of dimension n>1. The main function shows how to create a 4-dimensional array of integers as an example.

EDIT: keep in mind that the example below is minimal for readability, in that it does not deallocate the array, nor does it do bounds checking on access. Adding this is trivial, and left to the programmer.

#include <stdio.h>
#include <stdlib.h>

template <typename T, int N>
struct array {
    array<T,N>() : data(NULL), offset((int*) malloc(sizeof(int)*N)){}
    array<T,N>(T *data, int *offset) : data(data), offset(offset){}
    array<T,N-1> operator[](int i){return array<T,N-1>(&data[i*offset[N]], offset);}
    bool resize(int *size){
        offset[N-1] = 1;
        int total_size = size[N-1];
        for(int i = N-2; i >= 0; i--){
            total_size *= size[i];
            offset[i] = offset[i+1]*size[i+1];
        }
        return (data = (T*) realloc (data, total_size*sizeof(T)));
    }
    T *data;
    int *offset;
};

template <typename T>
struct array<T,1>{
    array<T,1>(T *data, int *offset) : data(data){}
    T& operator[](int i){return data[i];}
    T *data;
};

int main () {
    array<int, 4> a;

    // create array with dimensions [1][3][3][7]
    int size[4] = { 1, 3, 3, 7 };
    a.resize(size);               

    a[0][1][2][3] = 123;

    return 0;
}

Enjoy.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiongenesysView Question on Stackoverflow
Solution 1 - C++jamesdlinView Answer on Stackoverflow
Solution 2 - C++Pavel RadzivilovskyView Answer on Stackoverflow
Solution 3 - C++Jiří PospíšilView Answer on Stackoverflow
Solution 4 - C++tePerView Answer on Stackoverflow
Solution 5 - C++MoiaView Answer on Stackoverflow
Solution 6 - C++gospesView Answer on Stackoverflow