为什么我不能将指定的初始化器与非聚合的结构一起使用



C++有一个很好的新功能:

struct Point{
int x;
int y;
int z; 
};
Point p{.x=47, .y=1701, .z=0};

但是,如果我添加了一个构造函数,那么我就被禁止使用漂亮的指定初始化器语法:

struct Point{
Point(int x, int y, int z = 0): x(x), y(y), z(z){}
int x;
int y;
int z; 
};
static Point p{.x=47, .y=1701, .z = 0};

错误:指定的初始化程序不能与非聚合一起使用类型"点">

我是否缺少了一些明显的东西(为什么如果指定的初始化器与具有公共成员但不是聚合的结构/类一起工作会很糟糕(,或者这只是一个没有添加到标准中的缺失功能?

聚合初始化(包括使用设计的初始化器进行初始化(绕过类的构造函数。

这对聚合来说不是问题,因为它们不允许有用户定义的构造函数。但是,如果允许对具有用户提供的构造函数(可以做一些有用的事情(的类进行这种初始化,这可能是有害的。

考虑这个例子:

class A
{
static std::map<A *, int> &Indices()
{
static std::map<A *, int> ret;
return ret;
}
public:
int dummy = 0;
A(int index)
{
Indices().emplace(this, index);
}
A(const A &) = delete;
A &operator=(const A &) = delete;

~A()
{
auto it = Indices().find(this);
std::cout << "Deleting #" << it->second << 'n';
Indices().erase(it);
}
};

如果您能够执行A{.dummy = 42};,那么您将在析构函数中获得UB,并且将无法防止这种使用。

指定了一个从C中提取功能的初始化器。大多数C++编译器也是C编译器,它首先是C功能。

他们添加了一个限制(初始值设定项按顺序排列(,并将其应用于与C类型匹配的C++类型,然后将其应用到C++中。大多数主要的C++编译器已经将其作为C++扩展(没有限制(;编译器实现者检查该限制是否合理;成本;添加该功能的成本非常低。

一旦有了构造函数,它就变成了一个更大的语言问题。初始值设定项是否引用构造函数参数?如果是,我们会遇到参数名称不唯一的问题。如果没有,那么当构造函数设置一个值,而初始化器设置一个不同的值时,我们如何处理它?

基本上,我们需要按名称的函数参数来获得带有构造函数的合理指定初始化器。这是一个新的功能,而不是简单地从C.中获得的

解决方法(针对命名参数(为:

struct RawPoint{
int x = 0;
int y = 0;
int z = 0;
};
struct Point {
Point( int x_, int y_, int z_ = 0 ):
x(x_), y(y_), z(z_)
{}
explicit Point( RawPoint pt ):
Point( pt.x, pt.y, pt.z )
{}
int x, y, z;
};

那么你可以做:

Point pt( {.x=3} );

通过访问CCD_ 2的指定初始化器功能。

这与在函数调用中指定初始值设定项的方式相同。

这也起作用:

struct Point:RawPoint {
Point( int x, int y, int z = 0 ):
RawPoint{x,y,z}
{}
explicit Point( RawPoint pt ):
RawPoint( pt )
{}
};

最新更新