Yes, you can calculate the offset of the base class with a constant expression, but it is not portable at all. You can use the little-known but documented gcc extension, which is also supported by clang. This is due to using __builtin_constant_p when used with the ?: Operator:
#define CB (&(B&)*(C*)nullptr) constexpr auto c_b_address = __builtin_constant_p CB ? CB : CB;
Note that I just used the CB macro to understand what is going on. This, of course, could be done by repeating the expression several times. By the way, I first learned about this trick in this question , which contains useful background information.
The main problem, as you probably already understand, is that neither reinterpret_cast nor equivalent C-style are allowed in constexpr expressions. Curiously, the C-style listing (as mentioned above) is accepted, but reinterpret_cast (which does not generate any code) is not. I also experimented with an obscure but apparently suitable operator ->* , but with mixed results:
#define CB1 (&(B&)*(C*)nullptr) #define CB2 (&((reinterpret_cast<C*>(nullptr))->*(&C::b))) #define CB3 (&(((C*)(nullptr))->*(&C::b))) #define CB4 (&(B&)*reinterpret_cast<C*>(nullptr)) #define CB CB1
Results with g ++ 4.8.3 and clang ++ 3.4:
g++ clang++
On my 64-bit Linux machine, only CB1 gives the correct answer 4 with both compilers. With gcc, both CB1 and CB2 work with or without __builtin_constant_p . Using clang, the only version that worked was CB1 with __builtin_constant_p .
Why should we believe in this intentional behavior?
As @ShafikYaghmour pretty reasonably asks in a comment: "Do you have a gcc or clang link that says they support this behavior?" I am going to expand this to ask "what documentation exists that indicates that this is a deliberate and not just a weird side effect?" After all, if someone is actually going to use this, it would be nice to have some indication that he may continue to exist in the future. This section attempts to resolve this issue.
For clang, the link is the source code itself , in which there is a comment in the VisitConditionalOperator function, which reads:
// If the condition (ignoring parens) is a __builtin_constant_p call, // the result is a constant expression if it can be folded without // side-effects. This is an important GNU extension. See GCC PR38377 // for discussion.
This, in turn, indicates gcc bugzilla error 38377 , which discusses this issue. In particular, in 2008, this error was marked as "__builtin_constant_p (t)? T: 1 is not considered a constant integer expression." In the discussion, he noted that for the conditional operator ( ?: ,
Yes, this is a (documented) special case required for compatibility with existing GNU C code.
And further
If you make a mistake in C, GCC will not be able to boot, as part of the GNU C GCC semantics depends on when it is built using GCC.
Given this, it seems that the behavior is both specific and deliberate, and because gcc itself relies on it, it is likely a fairly stable behavior.
However, all the usual caveats about using non-standard implementation details apply. If you can execute this at runtime, this becomes acceptable for both gcc and clang:
ptrdiff_t cb = (char *)(&(B&)*(C*)nullptr) - (char *)nullptr;