16

这与当前的 MSVC 编译器编译得非常好:

struct Foo
{
} const foo;

但是,它无法使用当前的 g++ 编译器进行编译:

error: uninitialized const 'foo' [-fpermissive]
note: 'const struct Foo' has no user-provided default constructor

如果我自己提供一个默认构造函数,它可以工作:

struct Foo
{
    Foo() {}
} const foo;

这是 MSVC 过于宽松的另一种情况,还是 g++ 在这里过于严格?

4

4 回答 4

15

C++03 标准:

8.5 [dcl.init] 第 9 段

如果没有为对象指定初始化程序,并且该对象是(可能是 cv 限定的)非 POD 类类型(或其数组),则该对象应默认初始化;如果对象是 const 限定类型,则基础类类型应具有用户声明的默认构造函数。

从上面看,gcc 中的错误似乎是完全有效的。

于 2011-11-11T10:38:14.790 回答
5

[2003: 8.5/9]: 如果没有为对象指定初始化程序,并且该对象是(可能是 cv 限定的)非 POD 类类型(或其数组),则该对象应默认初始化;如果对象是 const 限定类型,则基础类类型应具有用户声明的默认构造函数。否则,如果没有为非静态对象指定初始化器,则该对象及其子对象(如果有)具有不确定的初始值;如果对象或其任何子对象是 const 限定类型,则该程序是非良构的。

和:

[n3290: 8.5/11]: 如果没有为对象指定初始化器,则该对象是默认初始化的;如果不执行初始化,则具有自动或动态存储持续时间的对象具有不确定的值。[注意:具有静态或线程存储持续时间的对象是零初始化的,请参见 3.6.2._ —end note_ ]

[n3290: 8.5/6]:默认初始化类型的对象T意味着:

  • 如果是(可能是 cv 限定的)类类型(第 9 条),则调用 T 的默认构造函数(如果没有可访问的默认构造函数T,则初始化是非良构的);T
  • 如果T是数组类型,则每个元素都是默认初始化的;
  • 否则,不执行初始化。

如果程序要求对 const 限定类型的对象进行默认初始化TT则应是具有用户提供的默认构造函数的类类型。

因此,MSVC 在这里比这两个标准都更宽松。

于 2011-11-11T10:41:22.683 回答
2

我不知道标准的确切措辞,但 g++ 中的错误似乎比什么都不说的选项更明智。考虑一下:

struct X {
   int value;
};
const X constant; // constant.value is undefined

在用户提供默认构造函数的情况下(即使它什么都不做),编译器将调用该构造函数并且对象将被初始化(通过您在构造函数中实现的任何初始化定义)。

于 2011-11-11T10:35:21.073 回答
0

C++17 更新

C++17 对 const 限定类类型具有默认构造函数的要求增加了一些细微差别。该标准现在定义了“const-default-constructable”概念:

7默认初始化T 类型的对象意味着:

(7.1) — 如果T是(可能是 cv 限定的)类类型,则考虑构造函数。枚举适用的构造函数,并通过重载决议选择初始化器()的最佳构造函数。如此选择的构造函数被调用,带有一个空参数列表,以初始化对象。
(7.2) — 如果T是数组类型,则每个元素都是默认初始化的。
(7.3) — 否则,不执行初始化。

如果T 的默认初始化将调用T的用户提供的构造函数(不是从基类继承),或者如果

(7.4) — T的 每个直接非变体非静态数据成员M都有一个默认成员初始化器,或者,如果M是类类型X(或其数组),则X是 const-default-constructible, (7.5) — 如果T是具有至少一个非静态数据成员的联合,恰好一个变体成员具有默认成员初始值设定项, (7.6) — 如果T不是联合,则对于每个具有至少一个非静态数据成员的匿名联合成员 (如果有的话),恰好一个非静态数据成员有一个默认成员初始化器,并且(7.7) - 每个可能构造的T 基类都是 const-default-constructible。




如果程序要求对 const 限定类型T 的对象进行默认初始化,则T应为 const-default-constructible 类类型或其数组。

于 2018-10-23T16:54:40.573 回答