Ошибка преобразования указателя с помощью оператора Ternary
Я знаю, что у тройного оператора есть некоторые удивительные ограничения, но я был немного озадачен тем, что это не скомпилируется для меня:
void foo(bool b)
{
int* ptr = ((b) ? NULL : NULL);
}
Очевидно, что минимум должен был показать проблему. Ошибка:
[BCC32 Error] Unit11.cpp(20): E2034 Cannot convert 'int' to 'int *'
Компилятор - это менее 100% -конформирующий Embarcadero С++ Builder 2010, поэтому ошибка компилятора далека от невозможности...
ПРИМЕЧАНИЕ. Изменены Parens, чтобы избежать путаницы в моих намерениях.
ПРИМЕЧАНИЕ2: Я немного смутился о том, как я пришел к этой конструкции в первую очередь, так что здесь мое оправдание: я получал некоторые ошибки компиляции на строке типа a = b? c : d
, где b, c и d - все сложные выражения. Чтобы сузить его, я заменил c
и d
на NULL
, чтобы проверить, был ли b
виновником. На данный момент все попало в ад в ручную тележку.
Ответы
Ответ 1
NULL
- макрос, который расширяется до 0
(или некоторого целочисленного постоянного выражения со значением 0
, например, (1 - 1)
). Это не иначе "особенное".
Любое целочисленное постоянное выражение со значением нуля может использоваться как константа нулевого указателя, что является причиной того, что int* ptr = 0;
разрешено. Однако здесь выражение b ? 0 : 0
; это не является интегральным постоянным выражением (b
не является константой); его тип int
, который неявно конвертируется в int*
Обходным путем было бы явно указать, что вы хотите тип указателя:
int* const null_int_ptr = 0;
int* ptr = b ? null_int_ptr : null_int_ptr;
Пример немного надуман, хотя: обычно, когда вы используете условный оператор, по крайней мере один из аргументов на самом деле является типом указателя (например, b ? ptr : 0
); когда один из операндов является типом указателя, 0
неявно преобразуется в тот же самый тип указателя и, следовательно, тип всего условного выражения является типом указателя, а не int
.
Единственный случай, когда вы можете иметь эту "проблему", - это то, где константа нулевого указателя используется как второй, так и третий операнды условного оператора, что довольно странно.
Ответ 2
Ваша проблема в том, что в вашей системе NULL
определяется как 0
, который считается int в контексте тернарного оператора. Если вы static_cast
один из операндов на int*
, он должен автоматически продвигать другой.
Но зачем использовать такую конструкцию в первую очередь?
Ответ 3
NULL
может быть определен как имеющий тип int
или даже long
, поэтому тернарный оператор имеет тот же тип. Там нет неявного преобразования в тип указателя, поэтому компилятор генерирует ошибку.
Полученная здесь заключается в том, что существует неявное преобразование из константного целочисленного выражения, которое оценивается до нуля (позорная константа нулевого указателя).
Возможное решение здесь - это явное выражение:
int* ptr = b ? (int*) NULL : NULL;