我真的需要为const对象实现用户提供的构造函数吗?

aby*_*s.7 42 c++ constructor const language-lawyer c++11

我有代码:

class A {
  public:
    A() = default;

  private:
    int i = 1;
};

int main() {
  const A a;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

它在g ++上编译很好(参见ideone),但在clang ++上失败并出现错误:

const类型'const A'的对象的默认初始化需要用户提供的默认构造函数

我在LLVM错误跟踪器上报告了这个问题,并使其无效.

我认为试图说服铿锵的开发者绝对毫无意义.另一方面,我没有看到这种限制的原因.


任何人都可以建议,如果C++ 11标准以某种方式暗示此代码无效?或者我应该向g ++报告错误?或许在语言规则方面有足够的自由来以多种方式处理这些代码?

Pot*_*ter 24

N3797§8.5/ 7说:

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

没有进一步的例子或解释.我同意这看起来很奇怪.此外,在C++ 11中更新规则比在C++ 03中更严格,当类类型需要用户声明的构造函数时.(您的构造函数是用户声明的.)

解决方法是使用{},或使用Dietmar的聪明的类外inline定义来请求值初始化.

如果你在没有初始化程序的情况下添加另一个成员,GCC确实提供了一个诊断(相当不错的一个,指的是更新的C++ 11要求).

  private:
    int i = 1;
    int j;
Run Code Online (Sandbox Code Playgroud)

 

unmem.cpp:11:11: error: uninitialized const ‘a’ [-fpermissive]
   const A a;
           ^
unmem.cpp:1:7: note: ‘const class A’ has no user-provided default constructor
 class A {
       ^
unmem.cpp:3:5: note: constructor is not user-provided because it is explicitly defaulted in the class body
     A() = default;
     ^
unmem.cpp:7:9: note: and the implicitly-defined constructor does not initialize ‘int A::j’
     int j;
Run Code Online (Sandbox Code Playgroud)

海合会是指DR 253,为什么必须清空或完全初始化const对象初始化?这是标准中的一个未解决的问题,最后更新于2011年8月(后C++ 11),附注:

如果隐式默认构造函数初始化所有子对象,则不需要初始化程序.

因此,虽然Clang符合C++ 11(并且将遵循C++ 14的原则),但GCC正在实施标准化委员会的最新思想.

提起了一个GCC错误.我预测,-pedantic当错误得到修复时,您需要获得诊断.

  • GCC"bug"不会被修复,标准是,然后Clang将是.GCC的行为是[记录](http://gcc.gnu.org/gcc-4.6/changes.html#cplusplus),并且设计因为它破坏了太多的代码. (5认同)
  • FWIW GCC似乎试图做出明智的事情,如果数据成员未在声明点初始化,则会导致编译失败,如果是,则会发出错误.我很想把它称为标准中的一个错误. (4认同)

Die*_*ühl 23

请注意,您可以轻松地将您的类转换为具有用户定义的默认构造函数的类:

class A {
  public:
    A();

  private:
    int i = 1;
};

inline A::A() = default;
Run Code Online (Sandbox Code Playgroud)

根据8.4.2 [dcl.fct.def.default]第4段:

...如果特殊成员函数是用户声明的,并且未在其第一个声明中明确默认或删除,则由用户提供....

这隐含地指出,在第一个声明中未明确默认的函数不是用户提供的.结合8.5 [dcl.init]第6段

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

很明显,你不能使用默认构造函数默认它的第一个声明来初始化一个const对象.但是,如果它不是上面代码中所做的第一个声明,则可以使用默认定义.