The [] operator must be a non-static member function.

I have been able to write a class and overload the [] operator. But in my weird case, I would like to have an array of elements:

MyClass elements[6];

But I don't actually want element access

element[2]

to use regular pointer arithmetic; rather I'd like it to call my own [] operator.

Is there any way to do that?

Dani AI

Generated

Short answer: you can't change how built‑in arrays or pointers are indexed. For native arrays/pointers the expression a[i] is defined as *(a + i) — that's pointer arithmetic done by the compiler and there is no hook to replace it. operator[] can only be a non‑static member of a class, so only class (or wrapper) objects can intercept subscripting.

Given that, there are three practical options (all preserve readable x[ i ] syntax for callers):

  • Make the member a wrapper type (e.g. FieldArray / ArrayOfFields) that implements operator[] and returns a small proxy which does the offset math and performs the mmio read/write. This is the cleanest and safest route; it also documents “this is not a raw C array.” (This is the approach hinted at and the one later accepted.)
  • Make Field itself a descriptor/proxy (store a base offset or base pointer) so a single Field object implements operator[] to compute offset + index*size and return an access proxy. Then you declare a single Field member (not a native array).
  • If you need compile‑time offsets for every index, generate individual Field<Reg,Base+I*Size> members (or use template metaprogramming to produce a tuple/aggregate). That preserves compile‑time constants but is more complex.

Practical skeleton (wrapper+proxy idea):

template<typename RegT, std::uintptr_t Base, std::size_t N>
struct FieldArray {
  struct Proxy {
    volatile RegT* addr;
    operator RegT() const { return *addr; }
    Proxy& operator=(RegT v) { *addr = v; return *this; }
  };
  Proxy operator[](std::size_t i) const {
    return Proxy{ reinterpret_cast<volatile RegT*>(Base + i * sizeof(RegT)) };
  }
};

Caveats: if your current Field uses a compile‑time offset template parameter, you’ll need a runtime proxy (or a compile‑time generator). Also remember volatile/ordering, alignment and endianness for hardware access. Using a named wrapper (like FieldArray) is usually the simplest, most readable solution.

Recommended Answers

All 6 Replies

YES it is possible.

Its pretty simple once you understand the basis:

template <class T> class Array {
private:
  T* storage;
  int size;
public:
  Array(int arg = 10) {
    storage = new T[arg];
    size = arg;
  }
 
  ~Array() {
    delete[] storage;
    storage = 0;
  }

T& operator[](const int location) throw (const char *);
};

template <class T> T& MyArray<T>::operator[](const int location)
  throw (const char *) 
{
    if (location < 0 || location >= size) 
        throw "Invalid array access";
    else 
        return storage[location];
}

int main() {
  try {
     Array<int> x(13);
     x[0] = 4;
     x[1] = 5;
     cout << x[0] << endl;
     cout << x[1] << endl;
     x[13] = 84;
  }
  catch (const char* e) {
    cout << e << endl;
  }
}

The following is the output of the above example:
4
5
Invalid array access

Hope it helped, bye.

Well, that is not what I was looking for. As I said, I already know how to do that. In your example, you have only an instance of Array.

But!!!! I *DO* appreciate your reply because it "solved" my problem in a different way.

I wanted to be able to declare

C array[4];

to make it clear that array was an array of four. But I could declare a second type, maybe called CArray (or FooArray -- ArrayOfC, something). Just something to let the reader know that this is an array of elements.

I wanted to be able to declare

C array[4];

to make it clear that array was an array of four. But I could declare a second type, maybe called CArray (or FooArray -- ArrayOfC, something). Just something to let the reader know that this is an array of elements.

I dont get what you actually are trying to say. Mind if you give a small eg. coz you originally post stated:

rather I'd like it to call my own [] operator.

Also explain what do you mean by "my own [ ] operator"

O.k. I'll try this again.

I have an class, it is actually a class template, called Field. I am doing a hardware device driver in C++ and a Field is suppose to represent a physical register on the adapter. So, usually, you have a list of simple fields:

struct adapter {
    Field<uint16_t, 0x00> f1;
    Field<uint16_t, 0x02> f2;
    Field<uint16_t, 0x04> f3;
    ...
};

The first argument is the type (and size) of the register. The second is the offset. I don't want to let the C compiler lay out the fields for a couple of different reasons. (Sometimes there are holes, sometimes the same offset can be accessed different ways, etc).

Most registers are single entities like "interrupt register". But some fields are an array. In my case, the adapter has four ports and so sometimes you have a group of four register -- one for each port. I put in the [] operator in so I can do:

struct adapter {
    ...
    Field<uint16_t, 0x02> portControl;
    ...
};

    v = xxx.portControl[2];

The array subscript operator takes the offset, size, and index and computes a new offset equal to offset + (size * index). But when a naive user looks at the definition, he does not know that it is an array and then he may see the array subscripting and get really confused. So, I wanted to be able to do:

struct adapter {
    ...
    Field<uint16_t, 0x02> portControl[4];
    ...
};

    v = xxx.portControl[2];

and have it do the same thing.

But, with the idea that you gave me, I could do a number of different things. Like:

struct adapter {
    ...
    ArrayOfFields<uint16_t, 0x02, 4> portControl;
    ...
};

    v = xxx.portControl[2];

which I am beginning to like better.

Does that clarify what I was originally looking for?

The array subscript operator takes the offset, size, and index and computes a new offset equal to offset + (size * index).

In my previous implementation of the overloaded [ ] operator, make use of the logic you have stated and it should work out to be fine. After all the implementation of the [ ] is entirely in your hands so you can calculate a new offset and return the value corresponding to the new offset.

In my previous implementation of the overloaded [ ] operator, make use of the logic you have stated and it should work out to be fine. After all the implementation of the [ ] is entirely in your hands so you can calculate a new offset and return the value corresponding to the new offset.

I'm still not sure if you understand my original question.

I am/was trying to define what operator [] does for pointer to C, not C.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.