这段代码是否会产生物化的基纯右值,它应该编译吗?

Does this code result in a materialized base prvalue, and should it compile?

以下代码在 gcc 9.1 中编译 godbolt but not clang 8 godbolt:

class A {
protected:
    ~A() = default;
};

class B final : public A {
};

int main() {
    auto b = B{};
}

Clang 的错误:

<source>:10:16: error: temporary of type 'A' has protected destructor
    auto b = B{};
               ^
<source>:3:5: note: declared protected here
    ~A() = default;
    ^

哪个是正确的,为什么?

感谢评论中的澄清; 自 C++17 以来,B{} 是聚合的,即使它是从 A 派生的,因此将由无法访问 dtor。所以 clang 拒绝编译是正确的。标准:

no virtual, private, or protected (since C++17) base classes

但是使用 () 将按照标准说明工作。

基地的dtor可以public也可以保护

A common guideline is that a destructor for a base class must be either public and virtual or protected and nonvirtual

see the guideline of standard

与 C++11 相比,表达式 B()prvalue,而 auto b = B(); 是 move-construction 并且移动可能会被省略,在 C++17 中,没有移动。 prvalue 没有被移动。这是 value-initializing B() 并且完全等同于:

B();

Value Categories in C++17

是的,Clang 拒绝代码是正确的。

auto b = B{}; 中我们有一个聚合初始化,它直接发生在 main 函数中。所以这个函数必须能够调用 B 子类型的析构函数,以防在初始化过程中发生异常。

引自 N4861(最后一个 C++20 草案),[dcl.init.aggr]/8:

The destructor for each element of class type is potentially invoked from the context where the aggregate initialization occurs. [ Note: This provision ensures that destructors can be called for fully-constructed subobjects in case an exception is thrown. — end note ]

为了完整起见,引用 [class.dtor]/15:

[...] A program is ill-formed if a destructor that is potentially invoked is deleted or not accessible from the context of the invocation.