通过初始化列表返回 class 时的默认值(vs2015 vs vs2017)

Default values when returning a class via initializer list (vs2015 vs vs2017)

我正在寻找对以下观察结果的解释。 从 vs2017 开始,有问题的代码简称为:

#include <iostream>

class Range
{
public:
  double min = 0; // some default values here
  double max = 1;

  double getRange() const {return max-min;};
};

Range makeRange(double a, double b)
{
  return {a,b}; // the initializer list return in question
}

int main()
{
  const auto x = makeRange(4.0,5.0); // some example application
  std::cout << x.min << ", " << x.max << std::endl;
}

在此,class范围为"min"和"max"提供了默认值,并且可以通过"makeRange"中的初始化列表进行初始化。此代码在 VS2017 中编译和工作。

在 VS2015 中无法编译(错误 C2440:'return':无法从 'initializer list' 转换为 'Range')。但是,如果删除默认值,则

class Range
{
public:
  double min;
  double max;

  double getRange() const {return max-min;};
};

它在 vs2015 中编译和工作。它仍然会在 VS2017 中编译。但是,默认值是未定义的(我猜)。一旦添加了构造函数,就有了默认值

  Range():min(0),max(0){};

VS2017编译失败。 所以关于这个有两个问题:

  1. 我假设 VS2015 支持初始化列表。为什么第一个代码不能在 VS2015 中编译?为什么在删除默认设置后会出现这种情况?
  2. 为什么默认构造函数的定义会破坏 VS2017 中的初始化列表功能?设置成员本身的默认值显然有效。

您正在使用 aggregate initialization。这当然需要 Range 是聚合类型。聚合的定义在不同版本的标准之间进行了很多调整。

因此,在 C++11 中,具有默认成员初始值设定项的 class 不能是聚合,但从 C++14 开始它可以。看来VS2015用的是前者的定义,VS2017用的是后者。

具有用户提供的构造函数的 class 在任何版本的标准中都不是聚合。