下面显示的代码片段在 Coliru 和 Ideone 中编译,但根据 iso § 8.5 p6,它不应该,还是我错过了什么?



根据C++11标准§8.5 p6,我们有:

如果程序调用const限定类型T,T应为用户提供的类类型默认构造函数。

以下代码不应编译。但在科利鲁和伊迪翁都是如此。

class A{};
int main() {
const A a;
}

编辑:

当我试图理解这里发生了什么时,我最终得到了以下代码,它进行了编译(至少它符合标准,因为A有一个用户提供的构造函数)。但后来我想到了以下问题:哪一个Standard子句确实保证a.b.j用0初始化(请参阅下面Ideone中的代码)?

#include <iostream>
struct B { int j; B(){ std::cout << "B()" << 'n'; } };
struct A
{
struct B b;
int i;
public:
A(): i(1) { std::cout << "A()" << 'n'; }
};  
int main() {
const A a;
std::cout << a.b.j << 'n';
std::cout << a.i << 'n';
}

第1版:

很抱歉出现上面的编辑,但我仍然不使用Unixes。上周Dietmar Kühl提醒我注意这样一个事实:"大多数UNIXe从零初始化页面开始"。因此,由于初始化,a.b.j不是0,正如我所想的那样。事实上,我刚刚用VS2010编译了代码,a.b.j的结果是一个统一的值,正如预期的那样。因此,应忽略编辑中的问题。

但我很想知道clang++或g++是否也会显示第二个片段的错误。谢谢

研究了初始化和聚合的规则后,我得出结论,您是对的—这个在技术上是错误的

您的编译器正在走捷径,因为没有成员,因此实际上不需要初始化。(有趣的是,古老的GCC 4.1.2拒绝了该程序。)

不幸的是,我没有什么要引用的,因为在这种情况下根本没有覆盖[C++11: 8.5/6]的规则。

至于为什么标准不允许这样做,为什么要这样做?空类几乎没有用,我看不出有什么理由为这种边缘情况主动编写更广泛、更有用的规则的豁免。

考虑到第7.1.6.1节第2段中的注释

2[注意:声明变量const可能会影响其链接(7.1.1)以及其在常数表达式(5.19)中的可用性。如8.5所述,const限定类型的对象或子对象的定义必须指定初始值设定项或接受默认初始化--终止注]

看起来编译器确实有点奇怪。

不过,如果你要添加一个数据成员,代码将不会在ideone中编译,而是至少在MS VC++2010中编译。在你提供的引文中,没有提到任何关于数据成员的内容。

相关内容

最新更新