Clang documentation巧妙地解释了
如果类或结构没有用户定义的默认构造函数,则为C ++ 不允许你默认构造它的const实例 这([dcl.init],p9)
以下代码为Base
提供了这样一个用户定义的默认构造函数,但g ++和Clang不同意Derived
的默认构造函数是否是用户定义的,即使Derived
明确表示继承所有Base
构造函数(使用 new C++11 inheriting constructors feature )
#include <iostream>
class Base
{
public:
Base(): b_(0) {} // look! user-defined default constructor
void print() const { std::cout << b_ << "\n"; }
private:
int b_;
};
class Derived
:
public Base
{
using Base::Base; // does this constitute a user-defined default constructor?
};
int main()
{
Base const b;
b.print(); // 0 for g++ & CLang
Derived const d;
d.print(); // 0 for g++, Clang: "default initialization of an object of const type 'const Derived' requires a user-provided default constructor"
}
g ++ 4.8很高兴接受这段代码,但Clang 3.3却没有。标准说了什么?
注意:没有用户定义的Base
默认构造函数,g ++ 4.8和Clang 3.3都不接受Base const b;
(例如g ++ 4.7.2之前接受过)。鉴于g ++知道规则,我认为这意味着g ++将Derived
的默认构造函数视为用户定义的。但Clang 3.3认为不然。
更新:根据@JesseGood的回答,0/1参数构造函数永远不会被继承,我尝试将Base
构造函数更改为
Base(int b = 0, void* = nullptr): b_(b) {}
但它无法解决Clang错误。
答案 0 :(得分:7)
Clang是对的。
关于const实例的相关段落来自8.5p7:
如果程序要求默认初始化a的对象 const限定类型T,T应为具有用户提供的类类型 默认构造函数。
由于Base(): b_(0) {}
是用户提供的,Base const b;
没问题。
下一个重要部分是12.9p3:
对于继承的候选集中的每个非模板构造函数 构造函数除了没有参数的构造函数或a 具有单个参数的复制/移动构造函数,构造函数是 除非使用相同的构造函数特性隐式声明 有一个用户声明的构造函数,其中包含相同的签名 出现使用声明的类
这里重要的部分是粗体文字。我认为这排除了你的情况,因为Base()
是一个没有参数的构造函数。这意味着Derived
没有用户提供的默认构造函数(尽管仍然隐式声明了一个)。
这也意味着来自基类的默认,复制和移动构造函数从不继承。