常数 T{};作品,常量 T;当 T 是非 POD 时失败,
const T{}; works, const T; fails when T is a non-POD,
首先,我有一个具有默认值的结构
struct S {
int a = 1;
};
当gcc和clang都为non-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
None 以下尝试对 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
};
我唯一能做的就是明确地添加 constexpr S() { }
。 const S s;
在 const S s{};
时失败对我来说似乎真的是错误的,尤其是当类型不是聚合时。
标准让我觉得Clang是对的
N4296: 8.5/7
If a program calls for the default initialization of an object of a
const-qualified type T, T shall be a class type with a user-provided
default constructor
那么为什么 gcc 允许这样做,并且 S{};
不是默认初始化,即使类型不是 POD 或聚合?
const S s3;
被[dcl.init]/12覆盖:
If no initializer is specified for an object, the object is default-initialized.
因此,根据您的报价要求,必须存在 user-provided 默认构造函数。像这样添加一个
struct S {
int a = 1;
constexpr S(){}
};
然后 makes the declaration compile fine.
[..] especially when the type is not an aggregate.
S
在您的情况下是一个聚合,也是 const S s{}
有效的原因。 const S s{}
应用聚合初始化,一切正常。
如果 S
不是聚合,则
List-initialization of an object or reference of type T is defined as
follows:
- If
T
is an aggregate, aggregate initialization is performed (8.5.1).
- Otherwise, if the initializer list has no elements and
T
is a class type with a default constructor, the object is value-initialized.
现在考虑值初始化的定义:
To value-initialize an object of type T
means:
- if
T
is a
(possibly cv-qualified) class type (Clause 9) with either no default
constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized;
- if
T
is a (possibly
cv-qualified) class type without a user-provided or deleted default
constructor, then
the object is zero-initialized and the semantic constraints for default-initialization are checked, and if
T
has a non-trivial default constructor, the object is default-initialized;
默认的 ctor 确实很重要,因为成员有一个初始化器 ([class.ctor]/4.9),但这无关紧要,因为无论如何都会检查约束。因此 default-initialization 是,并且行
const S s{};
与
一样有效(或无效!)
const S t;
So why does gcc allow this
嗯:
所以看起来 gcc 是基于 DR 253 even though this is not resolved yet. We can see this from the the following gcc bug report 的,它说:
This is by design, because as DR 253 shows, the normative standard is flawed.
并且 gcc change that brought this into effect 表示:
Core 234 - allow const objects with no initializer or
user-provided default constructor if the defaulted constructor
initializes all the subobjects.
所以从技术上讲,clang
是正确的,而 gcc
不符合要求,但他们似乎相信 DR 253
会以对他们有利的方式得到解决。如果主要关注的是 不确定的初始值 据我所知这是完全合理的。此更改记录在 gcc 4.6 release notes:
中
In 4.6.0 and 4.6.1 G++ no longer allows objects of const-qualified
type to be default initialized unless the type has a user-declared
default constructor. In 4.6.2 G++ implements the proposed resolution
of DR 253, so default initialization is allowed if it initializes all
subobjects. Code that fails to compile can be fixed by providing an
initializer e.g.
struct A { A(); };
struct B : A { int i; };
const B b = B();
首先,我有一个具有默认值的结构
struct S {
int a = 1;
};
当gcc和clang都为non-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
None 以下尝试对 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
};
我唯一能做的就是明确地添加 constexpr S() { }
。 const S s;
在 const S s{};
时失败对我来说似乎真的是错误的,尤其是当类型不是聚合时。
标准让我觉得Clang是对的
N4296: 8.5/7
If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor
那么为什么 gcc 允许这样做,并且 S{};
不是默认初始化,即使类型不是 POD 或聚合?
const S s3;
被[dcl.init]/12覆盖:
If no initializer is specified for an object, the object is default-initialized.
因此,根据您的报价要求,必须存在 user-provided 默认构造函数。像这样添加一个
struct S {
int a = 1;
constexpr S(){}
};
然后 makes the declaration compile fine.
[..] especially when the type is not an aggregate.
S
在您的情况下是一个聚合,也是 const S s{}
有效的原因。 const S s{}
应用聚合初始化,一切正常。
如果 S
不是聚合,则
List-initialization of an object or reference of type T is defined as follows:
- If
T
is an aggregate, aggregate initialization is performed (8.5.1).- Otherwise, if the initializer list has no elements and
T
is a class type with a default constructor, the object is value-initialized.
现在考虑值初始化的定义:
To value-initialize an object of type
T
means:
- if
T
is a (possibly cv-qualified) class type (Clause 9) with either no default constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized;- if
T
is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized and the semantic constraints for default-initialization are checked, and ifT
has a non-trivial default constructor, the object is default-initialized;
默认的 ctor 确实很重要,因为成员有一个初始化器 ([class.ctor]/4.9),但这无关紧要,因为无论如何都会检查约束。因此 default-initialization 是,并且行
const S s{};
与
一样有效(或无效!)const S t;
So why does gcc allow this
嗯:
所以看起来 gcc 是基于 DR 253 even though this is not resolved yet. We can see this from the the following gcc bug report 的,它说:
This is by design, because as DR 253 shows, the normative standard is flawed.
并且 gcc change that brought this into effect 表示:
Core 234 - allow const objects with no initializer or user-provided default constructor if the defaulted constructor initializes all the subobjects.
所以从技术上讲,clang
是正确的,而 gcc
不符合要求,但他们似乎相信 DR 253
会以对他们有利的方式得到解决。如果主要关注的是 不确定的初始值 据我所知这是完全合理的。此更改记录在 gcc 4.6 release notes:
In 4.6.0 and 4.6.1 G++ no longer allows objects of const-qualified type to be default initialized unless the type has a user-declared default constructor. In 4.6.2 G++ implements the proposed resolution of DR 253, so default initialization is allowed if it initializes all subobjects. Code that fails to compile can be fixed by providing an initializer e.g.
struct A { A(); }; struct B : A { int i; }; const B b = B();