C ++: Тернарный оператор (условный оператор) и его правила неявного преобразования типов

Существуют ли правила неявного преобразования типов для аргументов тернарного оператора?

Тернарный оператор всегда должен возвращать один и тот же тип. Этот тип определяется исключительно вторым и третьим аргументом (1st ? 2nd : 3rd), поэтому оба аргумента преобразуются в этот тип. Как определяется этот тип?

Чтобы быть более конкретным, я протестировал пример:

class pointclass
{
    pointclass();

    pointclass( int i );    // (pointclass)(int)
    operator bool() const;  // (bool)(pointclass)
};

У меня есть класс (pointclass), который позволяет неявное преобразование из int в pointclass и неявное преобразование из pointclass в bool.

int i;
pointclass p;
bool b;

b ? p : i;  // (bool) ? (int)(bool)(pointclass) : (int)
b ? i : p;  // (bool) ? (int) : (int)(bool)(pointclass)

Используя тернарный оператор, я сравниваю pointclass и int. Компилятор использует неявное преобразование из pointclass в bool, а затем стандартное преобразование из bool в int. Это делается независимо от того, обмениваюсь ли я вторым и третьим аргументами. Почему не преобразуется int в pointclass?

Использование оператора сравнения намного проще:

p == i;     // (pointclass) == (pointclass)(int)
i == p;     // (int) == (int)(bool)(pointclass)

Тип аргументов просто определяется первым аргументом.

Но я не понимаю правил преобразования типов тернарного оператора. Для меня это похоже на использование способа большинства конверсий.


person dib    schedule 27.08.2015    source источник
comment
Да, в стандарте правила указаны в [expr.cond].   -  person chris    schedule 27.08.2015
comment
Кто-то более разбирающийся в Стандартных способах, чем я, может дать авторитетный ответ, но, как правило, они конвертируются в «ближайший» общий тип, в который они могут быть преобразованы.   -  person SergeyA    schedule 27.08.2015
comment
Если вы думаете, что C ++ делает забавные вещи, подумайте о бедных Java-парнях.   -  person Bathsheba    schedule 27.08.2015
comment
Правила изложены в 5.16 [expr.cond]. Какой из них представляет проблему?   -  person n. 1.8e9-where's-my-share m.    schedule 27.08.2015
comment
Проблема заключается в преобразовании в bool, при котором отбрасывается почти вся информация. Лучшим способом было бы предотвратить успешное неявное преобразование из bool.   -  person dib    schedule 27.08.2015
comment
Потому что мы просто понижаем, а не повышаем. Смотрите мой ответ.   -  person MatthewRock    schedule 27.08.2015
comment
@MatthewRock, какая иерархия? int не является классом, и если бы он был с каким-то Object базовым классом бога, он был бы его братом. Кроме того, если у вас есть базовый класс и производный класс, вы не можете уменьшить базовый класс, потому что вы даже не знаете, является ли его динамический тип этим производным классом.   -  person chris    schedule 27.08.2015


Ответы (1)


Цитата из MSDN:

Условные выражения имеют ассоциативность справа налево. Первый операнд должен быть целочисленного или указательного типа. Следующие правила применяются ко второму и третьему операндам:

Если оба операнда одного типа, результат будет того же типа.

Если оба операнда относятся к арифметическому или перечислимому типу, обычные арифметические преобразования (описанные в разделе «Арифметические преобразования») выполняются для преобразования их в общий тип.

Если оба операнда относятся к типам указателей или если один является типом указателя, а другой является константным выражением, значение которого равно 0, выполняется преобразование указателя для преобразования их в общий тип.

Если оба операнда относятся к ссылочным типам, выполняется преобразование ссылок для преобразования их в общий тип.

Если оба операнда относятся к типу void, общим типом является тип void.

Если оба операнда относятся к одному и тому же определяемому пользователем типу, этот тип является общим.

Если операнды имеют разные типы и хотя бы один из операндов имеет тип, определяемый пользователем, то правила языка используются для определения общего типа. (См. Предупреждение ниже.)

По сути, компилятор C ++ ищет общий тип для второго и третьего операндов. Если он может его найти, то это тип результата. Если он не может его найти, это приводит к ошибке времени компиляции.

Если вы хотите увидеть стандартное положение, вы можете увидеть правила в рабочем проекте для новейшего стандарта, 5.16 (стр. 129).

Что касается непреобразования int в pointclass - общее правило состоит в том, что вы всегда идете вниз по иерархии, а не вверх - представьте себе более продвинутую иерархию классов; где-то наверху могут быть десятки способов преобразовать оба типа в какой-то другой класс, но действительно ли это то, что вам нужно? Более того, определение того, какой класс использовать, может оказаться невозможным. Поэтому мы опустили глаза.

person MatthewRock    schedule 27.08.2015
comment
Спасибо за этот ответ. Я понял, что условный оператор всегда преобразует иерархию вниз, где стандартный тип ниже класса. Проблема возникла из-за неявных преобразований между этими стандартными типами. Я мог бы предотвратить эти преобразования, явно определив (неявные) операторы преобразования между pointclass и всеми стандартными типами, кроме bool как protected. Спасибо! - person dib; 27.08.2015