У меня есть код, подобный следующему:
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 выдает ошибку ни на одном. Кто прав?
Неоднозначность. (Кроме того, если вы останавливаетесь на TL; Dr, то language-lawyer
тег не может быть вашей чашкой чая. ^ _ ^)
У обоих кандидатов есть один const foo&
параметр, который одинаково связывается с const foo
или же foo
аргумент. Не появляются другие правила, которые бы предпочли ту или иную функцию.
Разбивая это против текущий рабочий проект C ++
В обоих случаях
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
В обоих случаях мы имеем определяемое пользователем преобразование состоящий из:
Если мы выберем конструктор, то «тип результата» будет «значением cv-неквалифицированной версии целевого типа, чей результирующий объект инициализируется конструктором» ([Dcl.init] /17.6.3), поэтому для обеих функций-кандидатов второе стандартное преобразование тождественность (bar
-> bar
).
в [Dcl.init] /17.6.3, выражение инициализатора будет аргументом для выбранного вызова, в двух случаях foo
а также const foo
соответственно.
bar::bar(const foo& foo)
foo
а также const foo
в const foo&
([Over.match.viable] / 4)const foo
совместим с обоими foo
а также const foo
как const
более квалифицированным, чем оба const
и ничего. [Dcl.init.ref] / 4const foo&
привязывается непосредственно к lvalue foo
и lvalue const foo
, [Dcl.init.ref] / 5foo::operator bar() const
const foo&
в обоих случаях ([Over.match.funcs] / 4)foo
а также const foo
в const foo&
([Over.match.viable] / 4)Оба Идентичность => Определяемая пользователем конверсия => Идентичность, то есть определяемые пользователем последовательности преобразования.
Можем ли мы установить ранжирование между последовательностями? Только если применяется одно из следующих
Последовательности преобразования неразличимый, то есть ни лучше, ни хуже
Является ли любая из этих функций «лучшей»? Только если применяется одно из следующих
bar
, но другой не является конструктором для базового класса bar
([Over.match.best] /1.9)Ни одна из них не является «лучшей» функцией, поэтому вызов плохо сформирован. [Over.match.best] / 2
Других решений пока нет …