这与当前的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 ++过于严格?
答案 0 :(得分:15)
C ++ 03标准:
8.5 [dcl.init]第9段
如果没有为对象指定初始化程序,并且该对象是(可能是cv限定的)非POD类类型(或其数组),则该对象应默认初始化;如果对象是const限定类型,则底层类类型应具有用户声明的默认构造函数。
从上面看,gcc中的错误似乎完全有效。
答案 1 :(得分:5)
[2003: 8.5/9]:
如果没有为对象指定初始值设定项,则为 object是(可能是cv限定的)非POD类类型(或数组 其中,该对象应默认初始化;如果对象是 const-qualified类型,底层类类型应具有 用户声明的默认构造函数。否则,如果没有初始化器 为非静态对象,对象及其子对象指定,如果 任何,具有不确定的初始值; 如果对象或任何 它的子对象属于const限定类型,程序格式不正确。
和
[n3290: 8.5/11]:
如果没有为对象指定初始化程序,则默认初始化对象; 如果没有初始化 执行时,具有自动或动态存储持续时间的对象具有 不确定的价值。 [注意:具有静态或线程存储的对象 持续时间为零初始化,见3.6.2._ -end note_]
[n3290: 8.5/6]:
要默认初始化,T
类型的对象意味着:
- 如果
T
是(可能是cv限定的)类类型(第9条),则调用T的默认构造函数(如果T
没有,则初始化不正确可访问的默认构造函数);- 如果
T
是数组类型,则每个元素都是默认初始化的;- 否则,不执行初始化。
如果程序要求对const限定类型
T
的对象进行默认初始化,T
应为具有用户提供的默认构造函数的类类型。
所以MSVC在这里比两个标准要求更宽松。
答案 2 :(得分:2)
我不知道该标准的确切措辞,但g ++中的错误似乎比不说任何内容的选项更明智。考虑一下:
struct X {
int value;
};
const X constant; // constant.value is undefined
不是在用户提供的默认构造函数的情况下(即使它什么都不做),编译器将调用该构造函数,并且该对象将初始化(通过初始化的任何定义你已经在构造函数中实现了。
答案 3 :(得分:0)
C ++ 17更新
C ++ 17在const限定的类类型具有默认构造函数的要求上增加了一些细微差别。现在,该标准定义了“ const-default-constructable”概念:
7要 default-initialize 类型为T的对象的意思是:
(7.1)—如果 T 是(可能是cv限定的)类类型,则考虑构造函数。列举了适用的构造函数,并通过重载决议为 initializer ()选择了最佳的构造函数。如此选择的构造函数被调用,并带有一个空的参数列表,以初始化 对象。
(7.2)—如果 T 是数组类型,则每个元素都将默认初始化。
(7.3)—否则,不执行初始化。
如果T的默认初始化会调用用户提供的T的构造函数(不是从基类继承),或者如果
,则类类型 T 是const-default-constructible的 (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可构造的类类型或其数组。 / p>