Выбранная перегрузка из набора функций преобразования несовместима между GCC и Clang.

Рассмотрим этот пример

      #include <iostream>
struct T{
    T() = default;
    T(T const&)  =default;
};
T global;
struct S{
    operator T(){
        std::cout<<"#1\n";
        return T{};
    }
    operator T&(){
      std::cout<<"#2\n";  
      return global;
    }
};

int main(){
   S s;
   T obj(s);
}

GCC выбирает, а Clang выбирает вместо этого, я считаю их неоднозначными. Согласно dcl.init#17.6.3

В противном случае (т. е. для остальных случаев инициализации копированием) определяемые пользователем преобразования, которые могут преобразовывать исходный тип в целевой тип или (при использовании функции преобразования) в его производный класс, перечисляются, как описано в [over. match.copy], а лучший выбирается через разрешение перегрузки ([over.match]) . Если преобразование не может быть выполнено или неоднозначно, инициализация имеет неправильный формат. Выбранная функция вызывается с выражением инициализатора в качестве аргумента; если функция является конструктором, вызов является значением prvalue неквалифицированной cv версии целевого типа, объект результата которого инициализируется конструктором. Вызов используется для прямой инициализации в соответствии с приведенными выше правилами объекта, который является местом назначения инициализации копирования.

Согласно over.match.copy#1.2

Когда типом выражения инициализатора является тип класса «cv S», рассматриваются неявные функции преобразования S и его базовых классов. При инициализации временного объекта ([class.mem]) для привязки к первому параметру конструктора, где параметр имеет тип «ссылка на cv2 T», а конструктор вызывается с одним аргументом в контексте прямой инициализации объекта типа «cv3 T» также рассматриваются явные функции преобразования. Те, которые не скрыты внутри S и дают тип, чья версия cv-unqualified является тем же типом, что и T, или является его производным классом, являются функциями-кандидатами. Вызов функции преобразования, возвращающий «ссылку на X», является glvalue типа X, и поэтому считается, что такая функция преобразования дает X для этого процесса выбора функций-кандидатов.

Следовательно, независимо от или же , они оба относятся к типу доходности . Они оба имеют неявный объект параметра с , поэтому [over.match.best#2.1] не может определить, какой из них лучший

для некоторого аргумента j ICSj(F1) является лучшей последовательностью преобразования, чем ICSj(F2), или, если это не так,

Единственная надежда, которая может определить, какая перегрузка является лучшей, падает на [over.match.best#2.2]

контекст представляет собой инициализацию путем определяемого пользователем преобразования (см. [dcl.init], [over.match.conv] и [over.match.ref]) и стандартной последовательности преобразования из возвращаемого типа F1 в целевой тип. (т. е. тип инициализируемого объекта) является лучшей последовательностью преобразования, чем стандартная последовательность преобразования из возвращаемого типа F2 в целевой тип.

Обе их стандартные последовательности преобразования являются преобразованиями идентичности. Следовательно, они должны быть неоднозначными. Однако GCC и Clang имеют свои интерпретации и несовместимы. Интересно, какая интерпретация правильная?

0 ответов

Другие вопросы по тегам