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
?
Каково общее правило, описывающее многошаговое неявное преобразование?
Там нет многошаговой определяемые пользователем неявное преобразование.
int -> bool -> A
разрешено, потому что int->bool
преобразование не определяется пользователем.
1 Преобразования типов объектов класса могут быть определены конструкторами
и по функциям преобразования. Эти преобразования называются пользовательскими
преобразования и используются для неявных преобразований типов (пункт 4), для
инициализация (8.5) и для явных преобразований типов (5.4, 5.2.9).2 Пользовательские преобразования применяются только там, где они однозначны
(10.2, 12.3.2). Преобразования подчиняются правилам контроля доступа (пункт 11).
Контроль доступа применяется после разрешения неоднозначности (3.4).3 [Примечание:
См. 13.3 для обсуждения использования преобразований в вызовах функций.
а также примеры ниже. —Конечная записка]4 Максимум один пользовательский
преобразование (конструктор или функция преобразования) применяется неявно
на одно значение.
Так как эта конструкция совершенно законна
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) в этом случае не рассматривается.