This is a follow up to Get pointer to object from pointer to some member with the caveat that my structs aren't standard layout.
Consider the following scenario:
struct Thing; // Some struct
struct Holder { // Bigger struct
Thing thing;
static void cb(Thing* thing) {
// How do I get a pointer to Holder here? Say, to access other fields in Holder?
// Can consider storing a void* inside thing, but that's avoiding the problem and not zero overhead either
}
};
// C function which takes a Thing and eventually calls the callback with the same Thing
void cfunc(Thing* thing, void(*cb)(Thing*) cb_ptr);
void run() {
Holder h;
cfunc(&h.thing, &Holder::cb);
}
Now, how do I get a pointer to Holder
inside cb
? Of course, I am prepared to do unsafe stuff (like reinterpret casting, etc) to tell the compiler my assumptions and accept undefined behaviour if my assumptions are violated.
The main issue seems to be that the info that the callback would always be called on the thing
passed in seems to be missing to the compiler. Notwithstanding that, the fact that cb
would only ever be called with the holder
's own thing
member (and by extension, only thing
s inside holder
s) also seems to be missing. This is important if I have multiple Thing
s and multiple (unique) callbacks associated with them.
Note that inheritance seems to make this pretty simple:
struct Thing; // Some struct
struct Holder : public Thing { // Bigger struct
static void cb(Thing* thing) {
Holder* holder = (Holder*)thing;
}
};
// C function which takes a Thing and eventually calls the callback with the same Thing
void cfunc(Thing* thing, void(*cb)(Thing*) cb_ptr);
void run() {
Holder h;
cfunc((Thing*)&h, &Holder::cb);
}
If I want multiple Thing
s, I just inherit multiple times (probably with intermediate types since I don't know how to cast to the base class if I have multiple of the same type) and that's it.
Coming back to the linked answer, offsetof
seems to be a decent solution till you run into the requirement of standard layout which is a no-go since I have both public and private data members.
Is there another way to do this without inheritance?
Bonus points if you can tell me why offsetof
requires standard layout and why mixing public and private isn't standard layout. At least theoretically, it seems like the compiler should be able to figure this out anyway, especially if structs ALWAYS have a consistent layout (maybe this isn't true?) in the program.