Привязка ссылок через оператор неоднозначного преобразования

#include <iostream>
using namespace std;

struct CL2
{
CL2(){}
CL2(const CL2&){}
};

CL2 cl2;

struct CL1
{
CL1(){}
operator CL2&(){cout<<"operator CL2&"; return cl2;}
operator const CL2&(){cout<<"operator const CL2&"; return cl2;}
};

CL1 cl1;

int main()
{
CL1 cl1;
CL2 cl2 (cl1);
}

И clang, и gcc предоставляют неоднозначный оператор преобразования, но Visual Studio компилирует нормально и печатает «оператор const CL2&». Как должно быть правильно в соответствии со стандартом?
Как я понимаю, преобразование CL1 в const CL2& находится в контексте инициализации копирования (как часть прямой инициализации объекта cl2). Я видел черновик n4296, [over.match.copy]:

Предполагая, что «cv1 T» является типом объекта, который инициализируется,
с типом класса T функции-кандидаты выбираются следующим образом:
— Конвертирующие конструкторы (12.3.1) из T являются кандидатами
функции.
— когда тип выражения инициализатора является
тип класса «cv S», неявные функции преобразования S и его
базовые классы считаются. При инициализации временной привязки
к первому параметру конструктора, где параметр имеет тип
«Ссылка на возможно c-квалифицированную T» и конструктор называется
с одним аргументом в контексте прямой инициализации
объект типа «cv2 T», явные функции преобразования также
считается. Те, которые не скрыты в S и дают тип, чей
cv-неквалифицированная версия того же типа, что и T, или является производным классом
из них являются кандидатами функции. Функции преобразования, которые возвращают
«Ссылка на X» возвращает lvalues ​​или xvalues, в зависимости от типа
ссылка типа X и, следовательно, считается, что дают X для этого
процесс выбора кандидатских функций.

То есть оба оператора преобразования считаются возвращаемыми CL2 и const CL2 (а не просто CL2 без const), и остается решить, какое преобразование лучше: CL2 -> const CL2& или const CL2 -> const CL2&, Второй случай кажется более подходящим. Должно ли в этом контексте рассматриваться улучшение конверсии квалификации? Или оба случая являются преобразованием идентичности? Я не смог найти его в стандарте

8

Решение

Поскольку оба оператора преобразования имеют одинаковые подписи, единственным способом, которым один из них может быть предпочтительнее другого, является применение [over.match.best] / (1.4)…

— контекст является инициализацией путем пользовательского преобразования (см. 8.5,
13.3.1.5 и 13.3.1.6) и стандартную последовательность преобразования из возвращаемого типа F1 к типу назначения (то есть типу
инициализируемая сущность) является лучшей последовательностью преобразования, чем
стандартная последовательность преобразования из возвращаемого типа F2 к
тип назначения.

… Или (1.5):

— контекст является инициализацией функцией преобразования для прямого
привязка ссылки (13.3.1.6) ссылки на тип функции, […]

Понятно, что ни то, ни другое не применимо, отсюда и двусмысленность. Возможный способ устранения неоднозначности:

operator CL2&();
operator const CL2&() const;

демонстрация; Здесь исходная стандартная последовательность преобразования предыдущей перегрузки для неявного аргумента объекта лучше согласно [over.ics.rank] / (3.2.6), что решает [over.match.best] / (1.3).

4

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

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

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