聚合初始化不支持构造函数访问

Aggregate initialization does not uphold constructor access

给出下面的示例,我惊讶地发现尽管默认构造函数被显式删除(或为此设置为默认构造函数),聚合初始化仍然是可能的。

#include <iostream>

struct DefaultPrivate
{
      const int n_;
      static const DefaultPrivate& create();

    private:
      DefaultPrivate() = delete;
};

const DefaultPrivate& DefaultPrivate::create()
{
    static DefaultPrivate result{10};
    return result;
}

int main() {
    DefaultPrivate x; //Fails
    DefaultPrivate y{10};//Works
    return 0;
}

私有默认(或删除)构造和聚合初始化之间的关系是否在标准中未指定?

GCC 6.3 和 VCC 2017 都是这种情况

我问这个问题的原因是我希望更改对默认构造函数的访问会阻止 public 聚合初始化

来自 C++11,对于 list initialization

If T is an aggregate type, aggregate initialization is performed.

对于 C++11,aggregate 是以下类型之一:

...

class type (typically, struct or union), that has

  • ...

  • no user-provided, inherited, or explicit (since C++17) constructors (explicitly defaulted or deleted constructors are allowed) (since C++11)

  • ...

这意味着从C++11开始,显式删除构造函数的class仍被视为聚合类型,因此允许聚合初始化。

效果是:

Each direct public base, (since C++17) array element, or non-static class member, in order of array subscript/appearance in the class definition, is copy-initialized from the corresponding clause of the initializer list.

注意对于DefaultPrivate y{10};,在上面的过程中根本不会考虑默认构造函数,那么它被声明为deleteprivate就不会了重要的。

顺便说一句:对于 DefaultPrivate x; default initialization 执行,

if T is a non-POD (until C++11) class type, the constructors are considered and subjected to overload resolution against the empty argument list. The constructor selected (which is one of the default constructors) is called to provide the initial value for the new object;

所以尝试使用默认构造函数,但是 deleteed 然后编译失败。

如果你使用聚合初始化,比如DefaultPrivate x{};,代码也可以正常工作; n_ 将是 value initialized (and then zero initialized) 作为 0.

LIVE