Рассмотрим следующие два класса:
class B
{
public:
B() { }
B(const B& b) = delete; //Move ctor not implicitly declared
};
class A
{
public:
A() { }
operator B()
{
return B();
}
};
Я могу понять, почему этот код прекрасно компилируется:
A a;
B b = a;
Следуя правилам copy-initialization ,объект "a" преобразуется в значение типа B, и поскольку в C ++ 17 конструктор копирования больше не нужен, ошибки нет:
Если T является типом класса, а cv- Неограниченная версия другого типа не является T или не получена из T, или если T не является типом класса, но тип другого является типом класса, определяемые пользователем последовательности преобразования могут преобразовываться из другого типа в T(или для типа, полученного из T, если T является типом класса и доступна функция преобразования), и выбирается лучший из них с помощью разрешения перегрузки.Результат преобразования, который является prvalue временным (до C ++ 17) prvalue выражением (начиная с C ++ 17), если использовался конвертирующий конструктор, затем используется для прямой инициализации объекта.Последний шаг обычно оптимизируется, и результат преобразования создается непосредственно в памяти, выделенной для целевого объекта, но соответствующий конструктор (перемещение или копирование) должен быть доступен, даже если он не используется.(до C ++ 17)
Однако почему эта прямая инициализация списка тоже компилируется?
A a;
B b{ a };
Я не смог найти никакой формулировки в списке инициализация с указанием того, что компилятор должен попытаться преобразовать A в B в этом случае.Рассматривается только это разрешение перегрузки для конструкторов:
Если предыдущий этап не приводит к совпадению, все конструкторы T участвуют в разрешении перегрузки для набора аргументов, который состоит из элементов фигурной скобкиinit-list, с ограничением, что разрешены только не сужающие преобразования
Однако в этом случае конструктор копирования удаляется, поэтому не должен ли он быть выбран разрешением перегрузки?