Rya*_*ing 24 c++ gcc clang language-lawyer c++14
首先,我有一个结构,其中一个值具有默认值
struct S {
int a = 1;
};
Run Code Online (Sandbox Code Playgroud)
当gcc和clang都是非const/non-constexpr时,可以默认构造此类型.在两者之下,std::is_pod<S>::value是false.奇怪的行为如下:
S s1; // works under both
const S s2{}; // works under both
const S s3; // only works in gcc, clang wants a user-provided constructor
Run Code Online (Sandbox Code Playgroud)
以下尝试都没有对clang产生影响:
struct S {
int a = 1;
constexpr S() = default; // defaulted ctor
virtual void f() { } // virtual function, not an aggregate
private:
int b = 2; // private member, really not an aggregate
};
Run Code Online (Sandbox Code Playgroud)
我唯一可以做的就是constexpr S() { }明确添加这项工作.看来真的错了,我认为const S s;虽然失败const S s{};,特别是当类型不是聚集.
该标准让我觉得Clang是对的
N4296:8.5/7
如果程序要求对const限定类型T的对象进行默认初始化,则T应为具有用户提供的默认构造函数的类类型
那么为什么gcc允许这个,并且S{};不是默认初始化,即使类型不是POD或聚合?
Col*_*mbo 16
const S s3;
Run Code Online (Sandbox Code Playgroud)
[dcl.init]/12涵盖:
如果没有为对象指定初始化程序,则默认初始化该对象.
因此,根据引用的要求,必须存在用户提供的默认构造函数.添加一个这样的
struct S {
int a = 1;
constexpr S(){}
};
Run Code Online (Sandbox Code Playgroud)
然后使声明编译正常.
[..]特别是当类型不是聚合时.
S 在您的情况下是一个聚合,其原因const S s{}是有效的.应用聚合初始化const S s{},一切都很好.
如果S不是聚合,
列表初始化对象或类型T的引用定义如下:
- 如果
T是聚合,则执行聚合初始化(8.5.1).- 否则,如果初始化列表没有元素并且
T是具有默认构造函数的类类型,则对象将进行值初始化.
现在考虑值初始化的定义:
对值初始化类型的对象
T意味着:
- if
T是一个(可能是cv限定的)类类型(第9条),没有默认构造函数(12.1)或者是用户提供或删除的默认构造函数,那么该对象是默认初始化的;- 如果
T是没有用户提供或删除的默认构造函数的(可能是cv限定的)类类型,则该对象被零初始化并且检查默认初始化的语义约束,并且如果T具有非平凡的默认构造函数,则对象是默认初始化的;
默认的ctor确实非常重要,因为一个成员有一个初始化器([class.ctor] /4.9),但这是无关紧要的,因为无论如何都要检查约束.因此默认初始化它和行
const S s{};
Run Code Online (Sandbox Code Playgroud)
与...一样有效(或无效!)
const S t;
Run Code Online (Sandbox Code Playgroud)
那么为什么gcc允许这样做呢
好:
就现行标准而言,GCC不符合要求; 往上看.
有一个活跃的CWG问题,#253,创建于十五年前,涵盖了类似的情况.2011年会议上关于这一点的最后一点说明
如果隐式默认构造函数初始化所有子对象,则不需要初始化程序.
这是隐式默认构造函数的情况S,这将使您的所有行有效.
海湾合作委员会开发商(例如此处)暗示,由于委员会基本同意上述决议,海湾合作委员会目前的行为是可行的,不应进行调整.所以人们可以说GCC是正确的,标准被打破了.
所以看起来gcc正基于DR 253,即使这还没有解决.我们可以从以下gcc错误报告中看到这一点:
这是设计上的,因为正如DR 253所示,规范标准存在缺陷.
核心234 - 如果默认构造函数初始化所有子对象,则允许const对象不使用初始化程序或用户提供的默认构造函数.
所以从技术上讲clang是正确的,gcc并且不符合要求,但似乎他们相信DR 253会得到有利于他们的解决.如果主要关注点是不确定的初始值,这是完全合理的,据我所知.gcc 4.6发行说明中记录了此更改:
在4.6.0和4.6.1中,G ++不再允许对const限定类型的对象进行默认初始化,除非该类型具有用户声明的默认构造函数.在4.6.2中,G ++实现了DR 253的建议解析,因此如果初始化所有子对象,则允许默认初始化.可以通过提供初始化程序来修复无法编译的代码
Run Code Online (Sandbox Code Playgroud)struct A { A(); }; struct B : A { int i; }; const B b = B();
| 归档时间: |
|
| 查看次数: |
601 次 |
| 最近记录: |