Это интересно. Существует два способа прочитать критическую часть раздела 13.3.3.Исходный пример должен обязательно вызвать шаблон функции, но версия, в которой удаляется один из не-шаблонов, может считаться неоднозначным.
13.3.3:
жизнеспособная функция F1
определяется быть лучше функция, чем другой жизнеспособной функции F2
, если для всех аргументов я, ICS_i (F1
) не хуже последовательность преобразования чем ICS_i (F2
), а затем
для некоторого аргумента J, ICS_j (F1
) является лучшей, чем последовательность преобразования ICS_j (F2
), или, если не то, что,
контекст инициализации с помощью пользовательского преобразования (см 8.5, 13.3.1.5, 13.3.1.6 и) и стандартная последовательность преобразования из возвращаемого типа F1
в тип назначения (то есть тип инициализируемого объекта) является лучшей последовательностью преобразования, чем стандартная последовательность преобразования из возвращаемого типа F2
в тип назначения или, если это не так,
F1
- это не шаблонная функция, а F2
- это специализированная функция, или, если нет,
F1
и F2
являются функции шаблона специализации, а шаблон функции для F1
более специализированы, чем шаблон для F2
в соответствии с частичными правилами порядка, описанные в 14.5.6.2.
Если есть только одна жизнеспособная функция, которая является лучшей функцией, чем все другие жизнеспособные функции, то она выбирается с помощью разрешения перегрузки; в противном случае звонок плохо сформирован.
В примере, лязг правильно определяет набор из трех жизнеспособных функций-кандидатов:
C::operator int()
C::operator bool()
C::operator double<double>()
Третий шаблон функции специализация. (Я не думаю, что синтаксис выше является законным, но вы понимаете: в этот момент разрешения перегрузки он не рассматривается как шаблон, а как специализация с определенным типом функции.)
Единственное неявное преобразование Последовательность аргументов здесь (ICS1) является точной совпадением «lvalue C
» на «C&
» на неявный параметр, так что это не изменит ситуацию.
Этот пример - это точно ситуация, описанная во второй пуле, поэтому функция, возвращающая double
, явно лучше, чем две другие.
Вот где это странно: по буквальному чтению, operator int
также лучше, чем специализация шаблона, из-за третьей пули. «Подождите минуту, не следует« лучше »быть антисимметричным? Как вы можете сказать, F1
лучше, чем F2
И F2
лучше, чем F1
?» К сожалению, Стандарт явно не говорит ничего подобного. «Разве вторая пуля не имеет приоритета над третьей пулей из-за фразы« если не эта »?"Да, для постоянного F1
и F2
. Но стандарт не сказать, что удовлетворяющее второй пули для (F1,F2)
делает третью пулю (F2,F1)
не применяется.
Конечно, так как operator int
не лучше, чем operator bool
и наоборот, существует еще одна «жизнеспособная функция», которая является лучшей функцией, чем все другие жизнеспособные функции ».
Я не совсем одобряю это странное чтение, за исключением, возможно, сообщить об этом в качестве стандартного дефекта. Идти с этим было бы странно последствия (удаление перегрузка не лучший из этого примера изменяет программу от хорошо сформированной до двусмысленной!). Я думаю, что цель состоит в том, чтобы вторая пуля была рассмотрена в обоих направлениях до того, как третья пуля будет рассмотрена вообще.
Это будет означать, что шаблон функции должен быть выбран с помощью разрешения перегрузки, и это ошибка clang.
Ваше «странное чтение» стандарта очень интересно и на самом деле имеет для меня очень много смысла. Если я правильно ее понимаю, то ли оператор int лучше, чем шаблон, зависит от F1 и F2. Если мы рассмотрим F1 = op int, F2 = op, то при пуле 3 мы определим F1 лучше, чем F2 и остановимся. Но если мы рассмотрим F1 = op , F2 = op int, то на марке 2 мы лучше определим F1 и остановимся. Но если их три, то op int и op bool уже не лучше других, и, следовательно, нет двусмысленных –