Подтвердить что ты не робот

Является ли унаследованный конструктор по умолчанию также определяемым пользователем?

Документация Clang аккуратно объясняет, что

Если класс или структура не имеет пользовательского конструктора по умолчанию, С++ не позволяет вам по умолчанию построить экземпляр const, как это ([dcl.init], p9)

Следующий код имеет такой пользовательский конструктор по умолчанию для Base, но g++ и Clang не согласны с тем, является ли конструктор по умолчанию для Derived определяемым пользователем, хотя Derived явно наследует все Base конструкторы (используя конструкцию новых конструкторов наследования С++ 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 думает иначе.

UPDATE: на основе ответа @JesseGood, что конструкторы аргументов 0/1 никогда не наследуются, я попытался изменить конструктор Base на

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

но он не разрешает ошибку Clang.

4b9b3361

Ответ 1

Правильно. Clang.

Соответствующий отрывок из экземпляров const - от 8.5p7:

Если программа вызывает инициализацию по умолчанию объекта const-квалифицированный тип T, T должен быть типом класса с предоставленным пользователемконструктор по умолчанию.

Так как Base(): b_(0) {} предоставляется пользователю, Base const b; отлично.

Следующая важная часть - 12.9p3:

Для каждого конструктора без шаблона в наборе кандидатов унаследованных конструкторы , кроме конструктора без параметров или copy/move, имеющий один параметр, конструктор неявно объявляется с теми же характеристиками конструктора, если только есть конструктор с объявленным пользователем с той же сигнатурой в класс, где появляется декларация использования

Важная часть здесь - полужирный текст. Я считаю, что это исключает ваш случай, поскольку Base() - это конструктор, не имеющий параметров. Это означает, что Derived не имеет предоставленного пользователем конструктора по умолчанию (хотя он все еще неявно объявлен).

Это также означает, что конструкторы по умолчанию, копирование и перемещение из базового класса имеют никогда.