Какие из этих преобразований должны быть неоднозначными?

У меня есть код, подобный следующему:

class bar;

class foo
{
public:
operator bar() const;
};

class bar
{
public:
bar(const foo& foo);
};

void baz() {
foo f;
bar b = f;   // [1]

const foo f2;
bar b2 = f2; // [2]
}

GCC выдает ошибку в [2], но не [1]. Clang выдает ошибку на обоих, и, очевидно, MSVC выдает ошибку ни на одном. Кто прав?

13

Решение

Неоднозначность. (Кроме того, если вы останавливаетесь на TL; Dr, то language-lawyer тег не может быть вашей чашкой чая. ^ _ ^)

Спойлер

У обоих кандидатов есть один const foo& параметр, который одинаково связывается с const foo или же foo аргумент. Не появляются другие правила, которые бы предпочли ту или иную функцию.


Разбивая это против текущий рабочий проект C ++

В обоих случаях

  • мы выполняем инициализацию копирования ([Dcl.init] / 15)
  • тип назначения является типом класса ([Dcl.init] /17.6)
    • (X) выражение инициализатора не является prvalue ([Dcl.init] /17.6.1)
    • (X) тип источника не совпадает или не является производным от типа назначения ([Dcl.init] /17.6.2)
    • Пользовательские последовательности преобразования перечисляются из [Over.match.copy] и лучший, выбранный разрешение перегрузки.

T тип инициализируется, в обоих случаях это bar,
S тип выражения инициализатора, в двух случаях foo а также const foo соответственно.

  • преобразование конструкторов T являются кандидатами ([Over.match.copy] /1.1)
    • bar::bar(const foo& foo); является кандидатом
  • тип выражения инициализатора _cv_ S так неясно функции преобразования считаются: ([Over.match.copy] /1.2)
    • foo::operator bar() const не спрятан внутри foo или в пределах const fooи дает bar который так же, как Tи, следовательно, является кандидатом.

Таким образом, наш список кандидатов одинаков в обоих случаях:

  • bar::bar(const foo& foo)
  • foo::operator bar() const

В обоих случаях мы имеем определяемое пользователем преобразование состоящий из:

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

Если мы выберем конструктор, то «тип результата» будет «значением cv-неквалифицированной версии целевого типа, чей результирующий объект инициализируется конструктором» ([Dcl.init] /17.6.3), поэтому для обеих функций-кандидатов второе стандартное преобразование тождественность (bar -> bar).

Подмножество жизнеспособных функций-кандидатов [Over.match.viable]

в [Dcl.init] /17.6.3, выражение инициализатора будет аргументом для выбранного вызова, в двух случаях foo а также const foo соответственно.

bar::bar(const foo& foo)

  • Один аргумент в списке аргументов, ровно один параметр. ([Over.match.viable] /2.1)
  • Нет связанных ограничений ([Over.match.viable] / 3)
  • Последовательность неявного преобразования существует из обоих foo а также const foo в const foo& ([Over.match.viable] / 4)
  • Начальное стандартное преобразование Преобразование личности в обоих случаях: [Over.best.ics] / 5 => [Over.ics.ref] / 1 для прямой привязки ссылок:
    • const foo совместим с обоими foo а также const foo как const более квалифицированным, чем оба const и ничего. [Dcl.init.ref] / 4
    • const foo& привязывается непосредственно к lvalue foo и lvalue const foo, [Dcl.init.ref] / 5
  • жизнеспособный

foo::operator bar() const

  • Один аргумент в списке аргументов, ровно один неявный объект параметр. ([Over.match.viable] /2.1)
    • Неявный параметр объекта const foo& в обоих случаях ([Over.match.funcs] / 4)
  • Нет связанных ограничений ([Over.match.viable] / 3)
  • Последовательность неявного преобразования существует из обоих foo а также const foo в const foo& ([Over.match.viable] / 4)
  • Начальное стандартное преобразование Преобразование личности в обоих случаях см. выше.
  • жизнеспособный

Выберите лучшую жизнеспособную функцию [Over.best.ics]

Оба Идентичность => Определяемая пользователем конверсия => Идентичность, то есть определяемые пользователем последовательности преобразования.

Ранжирование конверсионных последовательностей over.ics.rank

Можем ли мы установить ранжирование между последовательностями? Только если применяется одно из следующих

  • (X) Не последовательности инициализации списка ([Over.ics.rank] / 3)
  • (X) Не стандартная последовательность преобразования ([Over.ics.rank] /3.2)
  • (X) Эти две последовательности не содержат «одну и ту же пользовательскую функцию преобразования или конструктор или […] инициализируют один и тот же класс в совокупной инициализации» ([Over.ics.rank] /3.3)

Последовательности преобразования неразличимый, то есть ни лучше, ни хуже

Лучшая жизнеспособная функция over.match.best

Является ли любая из этих функций «лучшей»? Только если применяется одно из следующих

Ни одна из них не является «лучшей» функцией, поэтому вызов плохо сформирован. [Over.match.best] / 2

2

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

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector