是否保证使用 {} 语法将 float 成员初始化为零?

Is a float member guaranteed to be zero initialized with {} syntax?

在C++17中,考虑这样一种情况,其中S是一个删除了默认构造函数和float成员的结构,当S用空大括号初始化时,标准保证的float成员是被零初始化?

struct A {
  int x{};
};

struct S
{
  S() = delete;
 
  A a;
  float b;
};

int main()
{
  auto s = S{}; // Is s.b guaranteed to be zero?
}

在我看来,cppreference.com不清楚,说两句:

If the number of initializer clauses is less than the number of members and basesor initializer list is completely empty, the remaining members and bases (since C++17) are initialized by their default member initializers, if provided in the class definition, and otherwise (since C++14) copy-initialized from empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates). If a member of a reference type is one of these remaining members, the program is ill-formed.

(from here),这意味着 b 保证为零

In all cases, if the empty pair of braces {} is used and T is an aggregate type, aggregate-initialization is performed instead of value-initialization.

(from here)

这意味着 b 不能保证为零。

还有一个讨论似乎暗示虽然不能保证,但所有已知的编译器无论如何都会进行零初始化:

The standard specifies that zero-initialization is not performed when the class has a user-provided or deleted default constructor, even if that default constructor is not selected by overload resolution. All known compilers performs additional zero-initialization if a non-deleted defaulted default constructor is selected.

相关

这是 C++ 的怪癖 fixed in C++20。同时,您可以将 explicit 添加到已删除的默认构造函数以强制结构变为非聚合,并使您的代码有保证的编译错误:

struct A {
  int x{};
};

struct S
{
  explicit S() = delete;
 
  const A a;
  const float b;
};

int main()
{
  auto s = S{}; // error: call to deleted constructor of 'S'
}

因为S是聚合,所以S{}会进行聚合初始化。当列表中没有初始化器时,标准中关于如何初始化成员的规则是 basically what you cited:

  • If the element has a default member initializer ([class.mem]), the element is initialized from that initializer.
  • Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list ([dcl.init.list]).

所以对于 b,这相当于 float b = {};。根据列表初始化规则,我们必须得到 all the way down to 3.10:

Otherwise, if the initializer list has no elements, the object is value-initialized.

而值初始化会将float初始化为0。