Следующая программа на С ++ компилируется без предупреждений во всех пробных компиляторах (gcc 4.6.3, llvm 3.0, icc 13.1.1, SolarisStudio 12.1 / 12.3):
struct CClass
{
template<class T>
operator T() const { return 1; }
operator int() const { return 2; }
};
int main(void)
{
CClass x;
return static_cast<char>(x);
}
Однако все компиляторы, кроме SolarisStudio, возвращают 2, SolarisStudio (любая версия) возвращает 1, что я считаю наиболее логичным результатом.
С помощью return x.operator char();
результаты во всех возвращаемых компиляторах 1.
Очевидно, что после выяснения этого я использовал последнее обозначение. Тем не менее, я хотел бы знать, какой из компиляторов является правильным и почему. (Можно подумать, что большинство правил, но это по-прежнему не объясняет Зачем.)
Этот вопрос, кажется, связан с вопросами SO Вот, Вот, а также Вот, но они «только» дают решения проблем, не дают никаких объяснений (что я все равно смог применить к своей конкретной проблеме).
Обратите внимание, что добавление дополнительного перегруженного оператора приведения, скажем, operator float() const { return 3; }
результаты во всех компиляторах, кроме SolarisStudio, жалуются на неоднозначность.
Первая (шаблонная) перегрузка должна быть выбрана.
Пункт 13.3.3 / 1 стандарта C ++ 11 определяет:
[…] жизнеспособная функцияF1
определяется как лучшая функция, чем другая жизнеспособная функция
F2
если для всех аргументовi
,ICSi(F1)
не хуже последовательности преобразования, чемICSi(F2)
, а потом— для некоторого аргумента
j
,ICSj(F1)
является лучшей последовательностью преобразования, чемICSj(F2)
или, если не так,— контекст является инициализацией пользовательским преобразованием (см. 8.5, 13.3.1.5 и 13.3.1.6) и
стандартная последовательность преобразования из возвращаемого типаF1
к типу назначения (т.е. тип
объект инициализируется) является лучшей последовательностью преобразования, чем стандартная последовательность преобразования из
тип возвратаF2
к типу назначения. [ пример:struct A { A(); operator int(); operator double(); } a; int i = a; // a.operator int() followed by no conversion // is better than a.operator double() followed by // a conversion to int float x = a; // ambiguous: both possibilities require conversions, // and neither is better than the other
—конец примера ] или же, если не то,
—
[…]F1
это не шаблонная функция иF2
это специализация шаблона функции, или, если не так,
Как вы можете видеть, тот факт, что первый оператор преобразования является шаблоном, становится релевантным только тогда, когда стандартная последовательность преобразования из его возвращаемого типа (char
в данном случае) к типу назначения (char
в данном случае) не лучше, чем стандартная последовательность преобразования из типа возврата не шаблонной перегрузки (int
в данном случае) к типу назначения (char
, в этом случае).
Тем не менее, стандартное преобразование из char
в char
является Полное совпадение, в то время как стандартное преобразование из int
в char
не является. Таким образом, третий пункт в п. 13.3.3 / 1 не применяется, а второй пункт применяется.
Это означает, что первая (шаблонная) перегрузка должна быть выбрана.
Первое точное совпадение, второе требует преобразования. Точные совпадения имеют приоритет перед конверсией.
Те другие вопросы, которые вы связали, в основном не связаны с вашими.
Несколько советов: не используйте операторы преобразования шаблонов. Назови это convert_to
вместо.