Унаследованные конструкторы, конструктор по умолчанию и видимость

Как заявлено [Namespace.udecl] / 18:

[…] Объявление-использование, которое именует конструктор, не создает синоним; вместо этого дополнительные конструкторы доступны, если они были бы доступны при использовании для создания объекта соответствующего базового класса, а доступность объявления using игнорируется. […]

Из-за этого следующий код не компилируется:

class B { protected: B(int) { } };
class D: B { using B::B; };
int main () { D d{0}; }

Он возвращает ошибку, которая более или менее одинакова со всеми основными компиляторами:

объявлен защищенным здесь

С другой стороны, следующий код компилируется:

class B { protected: B() { } };
class D: B { using B::B; };
int main () { D d{}; }

Разве он не должен скомпилироваться вместо этого по тем же причинам, которые привели к ошибке в предыдущем примере?
Что это позволяет компилировать?

8

Решение

Для второго случая наследующий конструктор не вступает в силу. По правилам удален неявно объявленный конструктор по умолчанию, что во 2-м случае класс D не нарушает (есть хорошо сформированный B::B() за D); компилятор объявит конструктор по умолчанию как встроенный открытый член для D, что делает D d{}; хорошо работать.

T имеет прямую или виртуальную базу, которая имеет удаленный конструктор по умолчанию, или она неоднозначна или недоступна из этого конструктора.

Для 1-го случая наследующие конструкторы вступает в силу:

(акцент мой)

Если разрешение перегрузки выбирает унаследованный конструктор, это
доступно, если оно будет доступно при использовании для создания объекта
соответствующего базового класса: доступность
использование-объявление, которое ввело это, игнорируется
.

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

Тогда это терпит неудачу из-за изоляции доступа.

3

Другие решения

class B { protected: B() { } };
class D: B { using B::B; };
int main () { D d{}; }

D в этом случае не имеет определяемого пользователем конструктора, поэтому компилятор генерирует один (открытый) для вас, который вызывает B::B (но не из-за using, что не имеет никакого эффекта в этом случае), этот конструктор, сгенерированный компилятором, затем вызывается main.

class B { protected: B(int) { } };
class D: B { using B::B; };
int main () { D d{0}; }

Даже если D здесь нет определяемого пользователем конструктора, сгенерированный компилятором неявно удаляется, потому что B имеет только конструктор, который принимает int, D также есть конструктор, который принимает int (using сделал это) но этот конструктор помечен protected и таким образом недоступен main,

6

По вопросам рекламы [email protected]