Инициализация копии c ++ и прямая инициализация, странный случай

Прежде чем продолжить чтение, прочтите, пожалуйста, Есть ли разница в C ++ между инициализацией копирования и прямой инициализацией? сначала убедитесь, что вы понимаете, о чем идет речь.

Сначала я резюмирую правило здесь (прочтите стандартные n3225 8.5 / 16, 13.3.1.3, 13.3.1.4 и 13. 3.1.5),

1) Для прямой инициализации все конструкторы будут рассматриваться как набор перегрузки, разрешение перегрузки выберет лучший из них в соответствии с правилами разрешения перегрузки.

2) Для инициализации копии и источника Тип такой же, как и целевой тип, или производный от целевого типа, правило такое же, как указано выше, за исключением того, что только конструкторы преобразования (конструкторы без явного указания) будут рассматриваться как набор перегрузки. Фактически это означает, что явные конструкторы копирования / перемещения не будут учитываться в наборе перегрузки.

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

3.1) Во время этой определяемой пользователем последовательности преобразования используются как ctors (неявные ctors), так и неявные функции преобразования будет рассматриваться в соответствии с правилами в 8.5 / 16 и 13.3.1.4.

3.2) Результат prvalue будет напрямую инициализировать целевой объект, как правила, перечисленные в (1), см. 8.5 / 16.

Ладно, хватит правил, давайте посмотрим на какой-нибудь странный код, о котором я понятия не имею, где мои рассуждения неверны, или просто все компиляторы ошибаются. Пожалуйста, помогите мне, спасибо.

struct A
{
    A (int) { }
    A() { }
    explicit A(const A&) { }
};
struct B
{
    operator A() { return 2; }
    //1) visual c++ and clang passes this
    //gcc 4.4.3 denies this, says no viable constructor available
};
int main()
{
    B b;
    A a = b;
    //2) oops, all compilers deny this
}

Насколько я понимаю, за (1),

operator A() { return 2; }

Поскольку в C ++ есть правило, согласно которому возврат функции рассматривается как инициализация копии, согласно приведенному выше правилу, 2 сначала неявно преобразуется в A, что должно быть в порядке, потому что A имеет конструктор A (int). Затем преобразованное временное значение prvalue будет использоваться для прямой инициализации возвращаемого объекта, что тоже должно быть в порядке, поскольку прямая инициализация может использовать явный конструктор копирования. Итак, GCC ошибочен.

Для (2),

A a = b;

Насколько я понимаю, сначала b неявно преобразуется в A оператором A (), а затем преобразованное значение должно использоваться для прямой инициализации a, что может конечно вызвать явный конструктор копирования? Таким образом, компиляция должна пройти, а все компиляторы ошибаются?

Обратите внимание, что для (2) и visual c ++, и clang имеют ошибку, похожую на: согласно приведенному выше правилу, 2 будет сначала неявно преобразовано в A, что должно быть в порядке, потому что A имеет конструктор A (int). Затем преобразованное временное значение prvalue будет использоваться для прямой инициализации возвращаемого объекта, что тоже должно быть в порядке, потому что прямая инициализация может использовать явный конструктор копирования. Итак, GCC ошибочен.

Для (2),

A a = b;

Насколько я понимаю, сначала b неявно преобразуется в A оператором A (), а затем преобразованное значение должно использоваться для прямой инициализации a, что может конечно вызвать явный конструктор копирования? Таким образом, компиляция должна пройти, а все компиляторы ошибаются?

Обратите внимание, что для (2) и visual c ++, и clang имеют ошибку, похожую на: согласно приведенному выше правилу, 2 сначала будет неявно преобразовано в A, что должно быть в порядке, потому что A имеет конструктор A (int). Затем преобразованное временное значение prvalue будет использоваться для прямой инициализации возвращаемого объекта, что тоже должно быть в порядке, потому что прямая инициализация может использовать явный конструктор копирования. Итак, GCC ошибочен.

Для (2),

A a = b;

Насколько я понимаю, сначала b неявно преобразуется в A оператором A (), а затем преобразованное значение должно использоваться для прямой инициализации a, что может конечно вызвать явный конструктор копирования? Таким образом, компиляция должна пройти, а все компиляторы ошибаются?

Обратите внимание, что для (2) и visual c ++, и clang имеют ошибку, похожую на: Затем преобразованное временное значение prvalue будет использоваться для прямой инициализации возвращаемого объекта, что тоже должно быть в порядке, потому что прямая инициализация может использовать явный конструктор копирования. Итак, GCC ошибочен.

Для (2),

A a = b;

Насколько я понимаю, сначала b неявно преобразуется в A оператором A (), а затем преобразованное значение должно использоваться для прямой инициализации a, что может конечно вызвать явный конструктор копирования? Таким образом, компиляция должна пройти, а все компиляторы ошибаются?

Обратите внимание, что для (2) и visual c ++, и clang имеют ошибку, похожую на: Затем преобразованное временное значение prvalue будет использоваться для прямой инициализации возвращаемого объекта, что тоже должно быть в порядке, потому что прямая инициализация может использовать явный конструктор копирования. Итак, GCC ошибочен.

Для (2),

A a = b;

Насколько я понимаю, сначала b неявно преобразуется в A оператором A (), а затем преобразованное значение должно использоваться для прямой инициализации a, что может конечно вызвать явный конструктор копирования? Таким образом, компиляция должна пройти, а все компиляторы ошибаются?

Обратите внимание, что для (2) и visual c ++, и clang имеют ошибку, похожую на: а затем преобразованное значение должно использоваться для прямой инициализации a, который, конечно, может вызывать явный конструктор копирования? Таким образом, компиляция должна пройти, а все компиляторы ошибаются?

Обратите внимание, что для (2) и visual c ++, и clang имеют ошибку, похожую на: а затем преобразованное значение должно использоваться для прямой инициализации a, который, конечно, может вызывать явный конструктор копирования? Таким образом, компиляция должна пройти, а все компиляторы ошибаются?

Обратите внимание, что для (2) и visual c ++, и clang имеют ошибку, похожую на: «Ошибка, невозможно преобразовать из B в A», но если я удалю явное ключевое слово в конструкторе копирования A, ошибка исчезнет ..

Спасибо за чтение.


редактировать 1

Потому что кто-то все еще не сделал этого. я не понял, что имел в виду, я цитирую следующий стандарт из 8.5 / 16,

В противном случае (т. е. для оставшихся случаи копирования-инициализации), определяемые пользователем последовательности преобразования, которые можно преобразовать из исходного типа в тип назначения или (когда используется функция преобразования) в их производные классы перечислены как описано в 13.3.1.4, и лучший один выбран из-за перегрузки разрешение (13.3). Если конверсия невозможно или неоднозначно, инициализация неправильно сформирована. В выбранная функция вызывается с выражение инициализатора как его аргумент; если функция является конструктор, вызов инициализирует временное резюме неквалифицированного версия типа назначения. В временное значение. Результат звонок (который является временным для случай конструктора) затем используется для прямая инициализация, согласно правила выше, объект, который пункт назначения копирование-инициализация. В некоторых случаях реализация разрешена исключить копирование, присущее этому прямая инициализация путем построения промежуточный результат прямо в инициализируемый объект; видеть 12.2, 12.8.

Обратите внимание, что упоминается прямая инициализация после пользовательского преобразования. Это означает, в моем понимании, что следующий код должен подчиняться правилам, которые я прокомментировал, что подтверждается обоими clang, coomeau online, visual c ++, но GCC 4.4.3 не работает как (1), так и (2). Хотя это странное правило, но оно следует из рассуждений стандарта.

struct A
{
    A (int) { }
    A() { }
    explicit A(const A&) { }
};

int main()
{
    A a = 2;    //1)OK, first convert, then direct-initialize
    A a = (A)2; //2)oops, constructor explicit, not viable here!
}

6
задан Community 23 May 2017 в 12:04
поделиться