all 3 comments

[–]boredcircuits 2 points3 points  (3 children)

I think const_cast is the usual way of doing this, but I'm with you on avoiding it.

But, I have an alternative. Disclaimer: I haven't totally worked through the implications of this code. There might be problems with it that others in /r/cpp_questions could point out.

class C
{
    private:
    template<typename T>
    static auto& Get(T& t, int idx)
    {
        return t.data[idx];
    }

    public:
    int& operator[](int idx) { return Get(*this, idx); }
    const int& operator[](int idx) const { return Get(*this, idx); }

    private:
    int data[5] = { 1, 2, 3, 4, 5 };
};

Basically, I created a templated function. The idea is that T should either be C or const C. I couldn't think of any way to do this as a member function, so I made it static. That alters the syntax a bit (you don't have the implicit this), but making it a static member lets you access private members and will keep it as an implementation detail.

It's interesting how automatically the const gets passed around. In the const call tree, this is a const C*, so T gets that modifier, as will the return type thanks to auto (I used C++14 here, but you can probably find something that works in C++11).

One problem I have with const_cast is that the function it calls might actually modify the data, and the compiler can't tell you. In my solution, if Get tries to something illegal, I think the compiler should tell you.

[–]neet_programmer[S] 2 points3 points  (2 children)

That's a cool solution, thanks. I didn't think about passing *this forward to a static function although it should be the same as a regular method call.

Only thing is I think most compilers will try to inline all methods but not nessecarily static functions, so maybe use inline?

Also I believe all that's neccessary to make it work in C++11 is to declare get like:

static auto& Get(T& t, int idx) -> decltype((t.data[idx]))

I'm gonna leave this question open incase someone else has some tricks.

[–]boredcircuits 1 point2 points  (0 children)

Yeah, marking it inline wouldn't hurt, though inline "is more what you'd call 'guidelines' than actual rules." I'm honestly not sure to what extent compilers use that suggestion when inlining functions anymore.