On Wednesday, June 26, 2019, 11:53:30 AM PDT, Chris Angelico <rosuav@gmail.com> wrote:

> I don't think you can define what "f->spam" means

Well, you can, but only the first half of what it means, so I don't think this changes your point.

If f is a pointer, then f->spam means to dereference the pointer f, then access the spam attribute of the result. If f is an instance of a user-defined class, rather than a raw pointer, it can redefine ->. But only to change the "dereference" part, not the "access the spam attribute" part. In other words, f->spam means something like (*(f.operator->())).spam and you can overload the operator->.

Of course, under very restricted conditions, you can do something like this:

    #include <iostream>

    struct pstatus;

    struct status { int eggs, spam; }

    struct pstatus {
        status *p;
        status* operator->() {
            return reinterpret_cast<status*>(reinterpret_cast<char*>(p) - sizeof(int));
        }
    };

    pstatus frob() {
        return pstatus{new status{1, 2}};
    }

    int main() {
        auto f = frob(); // eggs = 1, spam = 2
        std::cout << f->spam; // accesses eggs, and prints 1 rather than 2
        return 0;
    }

Compile that with g++ or clang++ with -std=c++11 (we don't actually need any C++11 feature here, the code's just a bit shorter and simpler with auto, etc.), and it should compile without warnings, and print out 1 rather than 2 when you run it.

The trick is that "access the spam attribute" actually means "access bytes 4-8 of the struct as an int", so if we have a pointer to 4 bytes before the start of the real struct, you get the int at bytes 0-4 of the real struct, which is the real eggs.

(Actually, we should be using the difference between offsetof(spam) and offsetof(eggs), not sizeof(int), so it would be legal even with non-default alignment. But so many tiny things could turn this code into undefined behavior, even with that change, like just adding a virtual method to status, or referencing f->eggs in code that doesn't even run… so let's not worry about bulletproofing it.)