GCC 8.2.1 和 MSVC 19.20 编译以下代码,但 Clang 8.0.0 和 ICC 19.0.1 无法编译。
// Base class.
struct Base {};
// Data class.
struct Data { int foo; };
// Derived class.
struct Derived : Base, Data { int bar; };
// Main function.
int main()
{
constexpr int Data::* data_p{ &Data::foo };
constexpr int Derived::* derived_p{ data_p };
constexpr int Base::* base_p{ static_cast<int Base::*>(derived_p) };
return (base_p == nullptr);
}
Clang 8.0.0 的错误信息如下:
case.cpp:16:33: error: constexpr variable 'base_p' must be initialized by a constant expression
constexpr int Base::* base_p{ static_cast<int Base::*>(derived_p) };
~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
我注意到它在两种情况下可以很好地使用 Clang 进行编译:
- 从最后一个定义中删除constexpr
- 将行
constexpr int Derived::* derived_p{ data_p };
替换为constexpr int Derived::* derived_p{ &Derived::bar };
。
constexpr 表达式(使 Clang 和 ICC 失败的表达式)应该编译吗?
最佳答案
我相信 GCC 和 MSVC 是正确的,这段代码应该可以编译。
data_p
指向Data
的成员foo
。 derived_p
通过指向成员转换的隐式指针指向Data
基类子对象的成员foo
[conv.mem]/2 .
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 ]
正如@geza 在他下面的评论中所指出的,类 Base
是 Derived
的基类,后者包含原始成员 Data::foo
在其 Data
基类子对象中(上面引用中的注释似乎是支持这种解释的进一步证据)。因此,用于初始化 base_p
的 static_cast
格式正确并且具有明确定义的行为。从 的
对象。Base
基类子对象的角度来看,结果指针指向 Derived
对象的 Data::foo
成员派生
要初始化一个 constexpr
对象,需要一个常量表达式 [dcl.constexpr]/9 。我们的表达式(static_cast
的结果)是一个核心常量表达式,因为 [expr.const]/2 中没有任何其他内容。它也是一个常量表达式,因为它是满足 [expr.const]/5 中规定的所有约束的纯右值。
关于c++ - 指向数据成员转换的 Constexpr 指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55844284/