Различные операторы литья, используемые разными компиляторами - программирование
Подтвердить что ты не робот

Различные операторы литья, используемые разными компиляторами

Следующая программа на С++ компилируется без предупреждений во всех компиляторах, которые я пробовал (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, жалующихся на двусмысленность.

4b9b3361

Ответ 1

Первую (шаблонную) перегрузку следует выбрать.

В пункте 13.3.3/1 стандарта С++ 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

-end example] или , если не тот,

- F1 - это функция без шаблона, а F2 - специализированная функция шаблона или, если не это,

[...]

Как вы можете видеть, факт, что первый оператор преобразования является шаблоном, становится актуальным только тогда, когда стандартная последовательность преобразования из ее возвращаемого типа (char в этом случае) к типу назначения (char, в этом case) не лучше стандартной последовательности преобразования из возвращаемого типа перегрузки без шаблонов (int, в данном случае) к типу назначения (char, в этом случае).

Однако стандартное преобразование из char в char является Точным соответствием, тогда как стандартное преобразование от int до char не является. Следовательно, третий пункт § 13.3.3/1 не применяется, а второй пункт.

Это означает, что следует выбрать первую (шаблонную) перегрузку.

Ответ 2

Первое - точное совпадение, второе - преобразование. Точные совпадения имеют приоритет над преобразованиями.

Эти другие вопросы, которые вы связываете, в основном не связаны с вашими.

Некоторые советы: не используйте операторы преобразования шаблонов. Назовите его convert_to.