C++ Can I overload the bracket [] operator to do different things if it on the LHS vs RHS of an assignment?

Viewed 105

I am looking to accomplish the following:

int x, y, z;

  1. foo[x] = y; acts like do_this(x,y);

  2. z = foo[x]; acts like z = do_that(x)

I can accomplish the first with a Foo class and a Helper class, where the operator[] returns by value a Helper class constructed with x, and the operator= for the Helper class is defined to run do_this(this->x, y). Like below:

class Foo {
    public:
    Helper operator[](int x) { 
        return Helper(x);
    }
};

class Helper {
    public: 
    Helper(x) {
        this->x = x;
    }
    void operator=(int y) {
        do_this(this->x, y);
    }
    private:
    int x;
};

What I can't figure out is how to accomplish (2). Is there a way to overload the operator[] so that it knows if it was used on the lhs vs the rhs?

2 Answers

Yes - give your Helper class a conversion function to int:

class Helper {
    public: 
    Helper(x){
        this->x = x;
    }
    Helper& operator= (int y) {
        do_this(this->x, y);
        return *this;
    }
    operator int() const {
        return do_that(this->x);
    }
    private:
    int x;
};

This will also allow other uses like product *= foo[x]; or func_taking_int(foo[x]), etc.

One potential catch is that some uses of auto or function templates would still just keep the type Helper, which might not be what's wanted - so users of Foo should still understand that this proxy sugar is going on. It could also be helpful to have some alternative syntax to explicitly get the int value for cases like that, in either Foo or Helper.

I'm not sure I've understood what you actually want to do, but you are might be able to use the const version of the operator[] vs. the non-const version. For example:

struct Foo {
    Z operator [] (int x) const {   // this last const is important
        return do_that(x);
    }

    Helper operator [] (int x) {
        // as you yourself have written.
    }
};

There are more tips and tricks to this, for forwarding arguments perfectly (a.k.a "perfect forwarding",) for being "const correct", and many other small things, but the gist of it is the above.

Related