Разрешение перегрузки. Является ли предпочтительным оператор прямого преобразования (вследствие исключения копирования)? - PullRequest
10 голосов
/ 30 апреля 2019

С учетом

struct E
{
};

struct P
{
    explicit P(E) {}
};

struct L
{
    operator E() {return {};}
    operator P() {return P{E{}};}
};

Согласно стандарту языка C ++ 17, должно ли выражение P{L{}} компилироваться?

Различные компиляторы дают разные результаты:

  • gcc (багажник): хорошо
  • gcc 8.3: ошибка (неоднозначная перегрузка)
  • GCC 7,4: хорошо
  • лязг (ствол): хорошо
  • лязг 8.0.0: ок
  • лязг 7.0.0: ок
  • msvc v19.20: ошибка (неоднозначная перегрузка)
  • icc 19.0.1: ошибка (более одного экземпляра конструктора соответствует)

1 Ответ

4 голосов
/ 30 апреля 2019

Я думаю, что правильное поведение по стандарту должно быть неоднозначным.

[dcl.init] /17.1:

Если инициализатором является (не заключенный в скобки) фигурный список инициализации или является = фигурный инициализированный список, объект или ссылка инициализируются списком.

[dcl.init.list] /3.6:

В противном случае, если T является типом класса, учитываются конструкторы. Применимые конструкторы перечисляются, и лучший выбирается через разрешение перегрузки ([over.match], [over.match.list]). Если для преобразования какого-либо из аргументов требуется сужающее преобразование (см. Ниже), программа некорректна.

И [over.match.list] просто говорит о выборе конструктора. У нас есть две жизнеспособные опции: P(E) с помощью L{}.operator E() и P(P&&) (неявный конструктор перемещения) с помощью L{}.operator P(). Нет лучше другого.

<ч />

Однако, это очень напоминает CWG 2327 :

struct Cat {};
struct Dog { operator Cat(); };

Dog d;
Cat c(d);

Что, как показывает проблема, в настоящее время вызывает Cat(Cat&&) вместо просто d.operator Cat() и предполагает, что мы должны также рассмотреть функции преобразования. Но это все еще открытый вопрос. Я не уверен, что gcc или clang сделали в ответ на эту проблему (или в ответ на подобные примеры, которые были подняты первыми), но, основываясь на ваших результатах, я подозреваю, что они решают, что функция прямого преобразования L{}.operator P() лучше соответствовать и просто сделать это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...