2015-12-06 2 views
8
#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); 
} 

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

Предполагая, что «CV1 T» типа объекта инициализации, с T типа класса, функция кандидатов выбираются следующим образом:
- Преобразовательные конструкторы (12.3.1) of T являются кандидатами функций.
- Если тип выражения инициализатора является классом типа «cv S», рассматриваются неявные функции преобразования S и его базовые классы . При инициализации временного привязки к первому параметру конструктора, где параметр имеет тип «ссылка на возможный Tv-квалифицированный T», а конструктор называется с единственным аргументом в контексте прямой инициализации объект типа «cv2 T», явные функции преобразования также относятся к . Те, которые не скрыты внутри S, и дают тип, для которого cv-неквалифицированная версия является тем же типом, что и T или является производным классом , являются функциями-кандидатами. Функции преобразования, которые возвращают значения «ссылки на X» или значения x в зависимости от типа ссылки типа X и поэтому считаются выходными для X процесс выбора функций-кандидатов.

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

+0

Похоже, Visual Studio * делает * компилирует ваш код. Но * IntelliSense * жалуется на объявление второго объекта. Насколько я понимаю, ваша проблема не в том, что вы думаете. Компилятор не знает, какую функцию оператора преобразования вызывать, поскольку вы не можете перегружать на основе типа возврата, но вы можете перегружать его на основе константы функции. Попробуйте 'operator const CL2 &() const {cout <<" operator const CL2 & "; return cl2; } ' – DeiDei

ответ

4

Поскольку оба оператора преобразования имеют идентичные подписи, единственным способом, которым можно было бы быть предпочтительнее другого, является применение [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; 

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

+0

Спасибо, но я не понимаю, почему у них одинаковые подписи (с учетом« const »)? И почему в [over.match.copy] написано «ссылка на X», но не «ссылка на cv X» (а X выводится как «CL2», но не как «const CL2»)? – user3514538

+0

@ user3514538 Первая стандартная последовательность преобразования рассматривается до второй. То есть если есть 'const', это доминирует. – Columbo

+1

@ user3514538 [over.match.copy] неприменим, поскольку он имеет дело с инициализацией копирования (в то время как ваш пример показывает прямую инициализацию). Кроме того, 'X' является произвольным и, следовательно, уже включает любые cv-квалификации. – Columbo