Несколько неявных преобразований для пользовательских типов не допускается?

class C {
public:
C() { }
};

class B {
public:
B(C c) { }
B() { }
};

class A {
public:
A(bool b) { }
A(B b) { }
};

int main() {
A a1 = true; // bool -> A        is allowed
A a2 = B();  // B -> A           is allowed

A a3 = 7;    // int -> bool -> A is allowed
A a4 = C();  // C -> B -> A      isn't allowed
}

Почему я могу использовать двухступенчатое неявное преобразование с bool но не могу использовать его с C?
Каково общее правило, описывающее многошаговое неявное преобразование?

11

Решение

Там нет многошаговой определяемые пользователем неявное преобразование.

int -> bool -> A

разрешено, потому что int->bool преобразование не определяется пользователем.

12.3 Преобразования [class.conv]

1 Преобразования типов объектов класса могут быть определены конструкторами
и по функциям преобразования. Эти преобразования называются пользовательскими
преобразования и используются для неявных преобразований типов (пункт 4), для
инициализация (8.5) и для явных преобразований типов (5.4, 5.2.9).

2 Пользовательские преобразования применяются только там, где они однозначны
(10.2, 12.3.2). Преобразования подчиняются правилам контроля доступа (пункт 11).
Контроль доступа применяется после разрешения неоднозначности (3.4).

3 [Примечание:
См. 13.3 для обсуждения использования преобразований в вызовах функций.
а также примеры ниже. —Конечная записка]

4 Максимум один пользовательский
преобразование (конструктор или функция преобразования) применяется неявно
на одно значение.

10

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

Так как эта конструкция совершенно законна

A a4((C()));

Проблема в том, что вы используете инициацию копирования. Действительно, ваш пример равен

A a4((A(C()));

8.5 / 16


Семантика инициализаторов следующая. Тип назначения — это тип объекта или ссылки, являющейся
инициализируется, а тип источника является типом выражения инициализатора. Если инициализатор не один (возможно,
в скобках), тип источника не определен.

Если тип назначения является (возможно, cv-квалифицированным) типом класса:

— В противном случае (т. Е. Для остальных случаев инициализации копирования) пользовательские последовательности преобразования
который может конвертировать из типа источника в тип назначения или (когда функция преобразования
используются для его производного класса, как описано в 13.3.1.4, и лучший
выбрано через разрешение перегрузки (13.3).

13.3.1.4/1


При условиях, указанных в 8.5, как часть инициализации копирования объекта типа класса, определяется пользователем
преобразование может быть вызвано для преобразования выражения инициализатора в тип инициализируемого объекта.

Разрешение перегрузки используется для выбора определяемого пользователем преобразования, которое будет вызвано. Предполагая, что «cv1 T»
тип инициализируемого объекта, с T типом класса, функции-кандидаты выбираются следующим образом:
— Конвертирующие конструкторы (12.3.1) из T являются функциями-кандидатами.

— Когда типом выражения инициализатора является тип класса «cv S», функции неявного преобразования
S и его базовые классы рассматриваются.

13.3.3.1/4


Однако при рассмотрении аргумента конструктора или пользовательской функции преобразования, которая является
кандидат на 13.3.1.3 при вызове для копирования / перемещения временного на втором шаге класса
copy-initialization, по 13.3.1.7 при передаче списка инициализаторов в виде одного аргумента или когда инициализатор
список содержит ровно один элемент и преобразование в некоторый класс X или ссылку на (возможно, cv-квалифицированную) X
рассматривается для первого параметра конструктора X, или 13.3.1.4, 13.3.1.5 или 13.3.1.6 во всех случаях, только
рассматриваются стандартные последовательности преобразования и последовательности преобразования эллипса.

Ваше пользовательское преобразование (C -> B) в этом случае не рассматривается.

1

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