Operator[][] overload

2018-12-31 14:08发布

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.

17条回答
梦寄多情
2楼-- · 2018-12-31 14:48
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.

查看更多
怪性笑人.
3楼-- · 2018-12-31 14:50

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.

查看更多
琉璃瓶的回忆
4楼-- · 2018-12-31 14:50

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).

查看更多
回忆,回不去的记忆
5楼-- · 2018-12-31 14:52

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;
}
查看更多
情到深处是孤独
6楼-- · 2018-12-31 14:56

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)).

查看更多
只靠听说
7楼-- · 2018-12-31 14:56

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; }
};
查看更多
登录 后发表回答