13

Clang 文档巧妙地解释了

如果类或结构没有用户定义的默认构造函数,C++ 不允许您像这样默认构造它的 const 实例 ([dcl.init], p9)

下面的代码有这样一个用户定义的默认构造函数Base,但 g++ 和 Clang 不同意默认构造函数是否Derived是用户定义的,即使Derived确实显式继承了所有Base构造函数(使用新的 C++11 继承构造函数功能

#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 错误。

4

1 回答 1

7

叮当是正确的。

关于 const 实例的相关段落来自 8.5p7:

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

既然Base(): b_(0) {}是用户提供的,Base const b;那就没问题了。

下一个重要部分是 12.9p3:

对于候选继承构造函数集中的每个非模板构造函数,除了没有参数的构造函数或具有单个参数的复制/移动构造函数,构造函数被隐式声明为具有相同的构造函数特征,除非用户声明的构造函数具有使用声明出现的类中的相同签名

这里的重要部分是粗体文本。我相信这排除了你的情况,因为Base()构造函数没有参数。这意味着Derived没有用户提供的默认构造函数(尽管仍然隐式声明了一个)。

这也意味着永远不会继承基类中的默认、复制和移动构造函数。

于 2013-05-27T22:29:53.220 回答