Search code examples
c++pointerscastingstatic-assert

How to do a static assert that a pointer cast is trivial?


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.


Solution

  • Based on a suggestion from MSalters, and an answer from C++, statically detect base classes with differing addresses?, here is the closest thing to an answer I can come up with. It's probably gcc-specific, and requires knowing some member of the base class:

    #pragma GCC diagnostic ignored "-Winvalid-offsetof"     // To suppress warning.
    BOOST_STATIC_ASSERT(offsetof(C, a) == offsetof(A, a));
    BOOST_STATIC_ASSERT(offsetof(C, b) != offsetof(B, b));
    #pragma GCC diagnostic warn "-Winvalid-offsetof"
    

    Obviously this is both inconvenient and scary (requires to know a member and to turn off a warning).