13

Clangのドキュメントはそれをきちんと説明しています

クラスまたは構造体にユーザー定義のデフォルト コンストラクターがない場合、C++ では、このような const インスタンスをデフォルトで構築することはできません ([dcl.init]、p9)。

次のコードには のユーザー定義のデフォルト コンストラクターがありますが、(新しい C++11 継承コンストラクター機能を使用して)すべてのコンストラクターを明示的に継承しているにもかかわらずBase、g++ と Clang は のデフォルト コンストラクターがユーザー定義であるかどうかについて意見が分かれています。DerivedDerivedBase

#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 はそうではないと考えています。

更新: 0/1 引数コンストラクターは継承されないという @JesseGood の回答に基づいて、Baseコンストラクターを次のように変更しようとしました

Base(int b = 0, void* = nullptr): b_(b) {}

ただし、Clang エラーは解決されません。

4

1 に答える 1

7

Clangは正しいです。

const インスタンスに関する関連する文章は、8.5p7 からのものです。

プログラムが const 修飾された型 T のオブジェクトの既定の初期化を呼び出す場合、T は、ユーザー提供の 既定のコンストラクターを持つクラス型でなければなりません。

Base(): b_(0) {}ユーザー提供なのでBase const b;大丈夫です。

次の重要な部分は 12.9p3 です。

パラメーターを持たないコンストラクターまたは単一のパラメーターを持つコピー/移動コンストラクターを除く、継承されたコンストラクターの候補セット内の各非テンプレート コンストラクターについて、コンストラクターは同じコンストラクター特性で暗黙的に宣言されます。 using 宣言が表示されるクラスの同じシグネチャ

ここで重要な部分は、太字のテキストです。Base()パラメータを持たないコンストラクタであるため、これはあなたのケースを除外すると思います。これはDerived、ユーザー提供のデフォルト コンストラクターがないことを意味します (ただし、暗黙的に宣言されています)。

これが意味することは、基本クラスからのデフォルト、コピー、および移動コンストラクターは決して継承されないということです。

于 2013-05-27T22:29:53.220 に答える