Constexpr pointer to data member conversion
I believe GCC and MSVC are correct, this code should compile.
data_p
points to the member foo
of Data
. derived_p
points to the member foo
of the Data
base class subobject of a Derived
via implicit pointer to member conversion [conv.mem]/2.
From [expr.static.cast]/12
A prvalue of type “pointer to member of
D
of type cv1T
” can be converted to a prvalue of type “pointer to member ofB
of type cv2T
”, whereB
is a base class ofD
, if cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. […] If classB
contains the original member, or is a base or derived class of the class containing the original member, the resulting pointer to member points to the original member. Otherwise, the behavior is undefined. [ Note: Although classB
need not contain the original member, the dynamic type of the object with which indirection through the pointer to member is performed must contain the original member; see [expr.mptr.oper]. — end note ]
As pointed out by @geza in his comment below, the class Base
is a base class of Derived
, the latter of which contains the original member Data::foo
in its Data
base class subobject (the Note in the quote above would seem to be further evidence in support of this interpretation). Thus, the static_cast
used to initialize base_p
is well-formed and has well-defined behavior. The resulting pointer points to the Data::foo
member of a Derived
object from the perspective of the Base
base class subobject of that Derived
object.
To initialize a constexpr
object, a constant expression is required [dcl.constexpr]/9. Our expression (the result of the static_cast
) is a core constant expression because there is nothing in [expr.const]/2 that would say otherwise. And it is also a constant expression because it is a prvalue that satisfies all the constraints laid out in [expr.const]/5.