构造函数干扰成员变量指定的初始化程序?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了构造函数干扰成员变量指定的初始化程序?相关的知识,希望对你有一定的参考价值。
有一段时间了,人们已经能够在GCC中使用“指定的初始化程序”:
struct CC{
double a_;
double b_;
};
CC cc{.a_ = 1., .b_ = 2.}; assert(cc.a_ == 1. and cc.b_ == 2.); // ok
CC cc{.bla = 0., .bli = 0.}; // compile error
但是,当我添加构造函数时,标签将被忽略。
struct CC{
double a_;
double b_;
CC(double a, double b) : a_{a}, b_{b}{}
};
CC cc{.a_ = 1., .b_ = 2.}; assert(cc.a_ == 1. and cc.b_ == 2.); // ok
CC cc{.b_ = 2., .a_ = 1.}; // compiles but labels don't matter only the order, confusing
CC cc{.bla = 2., .bli = 1.}; // compiles but labels don't matter, confusing
换句话说,带有构造函数的初始化器语法使得标签的行为就像注释一样!这可能非常令人困惑,但最重要的是,这很奇怪。
我用gcc 8.1 -std=c++2a
偶然发现了这个。
这是预期的行为吗?
参考:https://en.cppreference.com/w/cpp/language/aggregate_initialization
这是一个gcc bug,这仍然建立even with -pedantic,其中we should receive warnings for any extensions
...要获得标准所需的所有诊断,您还应指定-pedantic ...
和gcc声称支持P0329R4: Designated initializers
关于C++2a
模式according to the C++ Standards Support in GCC page的提议:
语言特写|提案| GCC有哪些? ... 指定的初始化器| P0329R4 | 8
为了使用Designated initializers,类型应该是聚合[dcl.init.list]p3.1:
如果braced-init-list包含指定的初始化列表,则T应为聚合类。指定初始化列表的指示符中的有序标识符应形成T的直接非静态数据成员中的有序标识符的子序列。执行聚合初始化(11.6.1)。 [例如:
struct A { int x; int y; int z; }; A a{.y = 2, .x = 1}; // error: designator order does not match declaration order A b{.x = 1, .z = 2}; // OK, b.y initialized to 0
- 末端的例子]
根据CC
,[dcl.init.aggr]不是聚合物:
聚合是一个数组或类(第12条) - (1.1) - 没有用户提供的,显式的或继承的构造函数(15.1), ....
gcc bug report
如果我们看看gcc bug report: Incorrect overload resolution when using designated initializers,我们在这个给定的例子中看到:
另一个测试案例,从Chromium 70.0.3538.9减少并被clang接受:
struct S { void *a; int b; }; void f(S); void g() { f({.b = 1}); }
这失败了
bug.cc: In function ‘void g()’: bug.cc:3:24: error: could not convert ‘{1}’ from ‘<brace-enclosed initializer list>’ to ‘S’ void g() { f({.b = 1}); } ^
该错误表明在重载解析期间完全忽略了字段名称,这也解释了最初报告的代码的行为。
似乎gcc在重载解析期间忽略字段名称。这将解释您所看到的奇怪行为,并在我们删除构造函数时获得正确的诊断。
编译器不应忽略指定初始值设定项的标签。带构造函数的所有这三个示例都应该是格式错误的。
您可能会因为C ++ 20指定的初始化程序功能与GCC的C样式指定初始化程序之间的冲突而导致此行为,由于GCC只是将它们提供给您,因此您可以隐式访问它们。如果GCC是正确的C ++ 20-compiliant,一旦你给了类型一个构造函数,它将不再是一个聚合,因此指定的初始化程序使用将是不正确的。
基本上,这是由非C ++引起的驱动程序错误 - 默认情况下编译器为您提供的标准行为。如果你关闭这个功能,你可能会遇到适当的编译错误。
以上是关于构造函数干扰成员变量指定的初始化程序?的主要内容,如果未能解决你的问题,请参考以下文章
java 静态代码块 代码块 构造函数 静态成员变量 成员变量的初始化顺序
Kotlin类的初始化 ② ( 主构造函数 | 主构造函数定义临时变量 | 主构造函数中定义成员属性 | 次构造函数 | 构造函数默认参数 )