I'm looking for an explanation of the following observation. Starting from vs2017 the code in question in short reads as:
#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;
}
in this, the class Range provides default values for "min" and "max" and can be initialized by the initializer list from "makeRange". This code compiles and works in VS2017.
In VS2015 it does not compile (error C2440: 'return': cannot convert from 'initializer list' to 'Range'). However, if the default values are removed such that
class Range
{
public:
double min;
double max;
double getRange() const {return max-min;};
};
it compiles and works in vs2015. It will still compile in VS2017. However, the default values are undefined (i guess). Once a constructor is added such that there are default values
Range():min(0),max(0){};
the compilation in VS2017 fails. So there are two questions about this:
You are using aggregate initialization. This of course requires Range
to be an aggregate type. The definition of aggregate has been tweaked a lot between different versions of the standard.
Thus, in C++11 a class with default member initializers couldn't be an aggregate, but starting with C++14 it can be. It appears that VS2015 uses the former definition and VS2017 the latter.
A class with user-provided constructors is not an aggregate in any version of the standard.