Let's say I have these types:
struct A {
int a;
};
struct B {
int b;
};
struct C : public A, public B {
int c;
};
A C*
pointer can be cast to A*
pointer without adjusting the actual address at all. But when C*
is cast to B*
, the value must change. I'd like to ensure that two related types I have can be cast to each other without a change in address (i.e. that there is no multiple inheritance, or that the base class is the first base of the derived class). This could be checked at run-time, e.g. like so
assert(size_t(static_cast<A*>((C*)0xF000) == 0xF000);
assert(size_t(static_cast<B*>((C*)0xF000) != 0xF000);
That works. But this information is known at compile time, so I'm looking for a way to do a compile-time assert on it. The obvious ways of converting the above to a static assert (e.g. replace assert
with BOOST_STATIC_ASSERT
give the error "a cast to a type other than an integral or enumeration type cannot appear in a constant-expression" with g++ 4.2.
Portability isn't too important. Using gcc extensions, or hacky template tricks would all be fine.
Update: Found that almost the same question has been asked before: C++, statically detect base classes with differing addresses?. Using offsetof()
is the only useful suggestion there too.
"I'd like to ensure that two related types can be cast to each other without a change in address (i.e. that there is no multiple inheritance, or that the base class is the first base of the derived class)."
Your "i.e." isn't correct. For instance, it's entirely possible that the first 4 bytes of Derived
are a vtable pointer, even when Base
isn't polymorphic. Yes, C++ compilers are easier if (1) the first base subobject is at offset 0, and (2) the vtable pointer is at offset 0. But those two goals are inherently at odds, and there is no clear better choice.
Now, the first part could be tested in theory. With standard-layout types, there would be no difference in offset_of(Base, first_member)
and offset_of(Derived, first_member)
. But in practice, offset_of
doesn't work for interesting types; it's UB. And the whole point of this check is to check a type, so it should fail reliably for nonstandard-layout types.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With