2015-08-27 6 views
9

Существуют ли правила для неявного преобразования типов для аргументов тройного оператора?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. Это делается независимо от того, могу ли я заменить 2-й и 3-й аргументы. Почему он не конвертирует int в pointclass?

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

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

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

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

+0

Да, правила находятся в [expr.cond] в стандарте. – chris

+0

Кто-то, более знакомый стандартными способами, чем я, может дать авторитарный ответ, но, как правило, они преобразуются в «самый близкий» общий тип, к которому они могут быть преобразованы. – SergeyA

+0

Если вы считаете, что C++ делает фанковые вещи, позаботьтесь о бедных парнях Java. – Bathsheba

ответ

6

Цитирование MSDN:

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

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

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

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

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

Если оба операнда имеют тип void, общий тип - тип void.

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

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

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

Если вы хотите увидеть стандартное положение, вы можете увидеть правила in working draft for newest standard, 5.16 (стр. 129).

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

+0

Благодарим вас за этот ответ. Я понял, что Условный оператор всегда преобразует иерархию, где стандартный тип ниже класса. Проблема возникла из-за неявных преобразований между этими стандартными типами. Я мог бы предотвратить эти преобразования, явно определяя (неявные) операторы преобразования между «pointclass» и всеми стандартными типами, кроме 'bool' как' protected'. Благодаря! – dib