Может ли каждая конструкция if-else быть заменена эквивалентным условным выражением?

(У меня нет серьезной потребности в этом ответе, я просто любопытен.)

может ли каждая конструкция if-else быть заменена эквивалентным условным выражением с помощью условного оператора ?:?

8 ответов


все ли конструкции if-else могут быть заменены эквивалентным условным выражением с помощью условного оператора?

нет, вы задали этот вопрос задом наперед. "тела" if/else содержат операторы, и невозможно превратить каждое утверждение в выражение, такие как try, while, break заявления, а также объявления. Однако многие "утверждения" на самом деле являются замаскированными выражениями:

++i;
blah = 42;
some_method(a,b,c);

все это операторы, которые состоят из одного выражения (increment, assignment, function-call, соответственно) и могут быть превращены в выражения внутри условного.

Итак, давайте перевернем вопрос, так как похоже, что вы действительно хотите знать, насколько эквивалентны операторы if/else троичным условным выражениям: можно ли заменить каждое условное выражение эквивалентными операторами if/else? почти все, да. Типичным примером является возвращение заявления:

return cond ? t : f;
// becomes:
if (cond) return t;
else return f;

, но и другие выражения:

n = (cond ? t : f);
// becomes:
if (cond) n = t;
else n = f;

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

T obj (cond ? t : f);
// becomes:
SomeType temp;
if (cond) temp = t;
else temp = f;
T obj (temp);

обратите внимание, что это гораздо более утомительно / громоздко и требует чего-то зависящего от типа, если SomeType не может быть сконструированным и назначенным по умолчанию.


на поверхности, нет. Условный оператор-это выражение (То есть он имеет значение), а if/else-оператор (таким образом, не имеет значения). Они удовлетворяют различные "потребности" в синтаксисе языка.

однако, поскольку вы можете игнорировать значения выражений, и поскольку любое выражение можно превратить в оператор, добавив точку с запятой, вы можете по существу эмулировать if / else с условным выражением и двумя вспомогательными функциями:

// Original code:
if (condition) {
  // block 1
}
else {
  // block 2
}

// conditional expression replacement:

bool if_block() {
  // block 1
  return true;
}

bool else_block() {
  // block 2
  return true;
}

// Here's the conditional expression.  bool value discarded:
condition ? if_block() : else_block();

впрочем, имея сказал Это, я не уверен, что это что-то большее, чем любопытство...


Нет, конечно, нет. По причинам, уже упомянутым, и не только!

#include <cstdlib>
#include <iostream>

int main()
{
    if(int i = std::rand() % 2)
    {
        std::cout << i << " is odd" << std::endl;
    }
    else
    {
        std::cout << i << " is even" << std::endl;
    }
}

проверьте, где объявлено is. Это не часто используемый метод, но его можно использовать в таких ситуациях, как COM, где каждый вызов возвращает HRESULT, который (почти всегда) равен нулю при успехе (S_OK), ненулевой при неудаче, поэтому вы можете написать что-то вроде:

if(HRESULT hr = myInterface->myMethod())
{
    _com_raise_error(hr);
}

тернарный оператор не может сделать ничего аналогичного.


if( cond )
    break;
else
    a=b;

не всегда можно заменить на ?: оператора. Вы можете часто (если не всегда) переосмысливать весь свой код, чтобы обеспечить эту замену, но, как правило, вы не можете поместить ничего, что контролирует выполнение в ?:. break, return, петель, throw, etc.


в принципе, да:

if (A) B; else C

становится

try {
  A ? throw TrueResult() : throw FalseResult();
  // or: throw A ? TrueResult() : FalseResult();
} catch (TrueResult) {
  B;
} catch (FalseResult) {
  C;
}

по сравнению с использованием процедур (которые более естественны), это позволяет break, continue, return etc. Это требует оценки A не с TrueResult/FalseResult но если вы используете эти исключения только для имитации if, это не будет проблемой.


использование условного оператора приводит к выражению, и оба потенциальных результата условного оператора должны быть "совместимыми" (конвертируемыми в один и тот же тип).

An if-else construct не нужно даже "возвращать" какой-либо тип, тем более один и тот же из обеих ветвей.


условный оператор ожидает, что оба элемента будут следовать за ? быть rvalues (так как результат условного оператора сам по себе является rvalue) - поэтому, хотя я не совсем эксперт по стандартам C/C++, моя интуиция будет заключаться в том, что следующее будет запрещено (или в противном случае, чрезвычайно плохой стиль кодирования...):

(condition) ? return x : return y;

в то время как версия if-else будет довольно стандартной:

if(condition) return x;
else return y;

Теперь, что сказал, не могли бы вы взять любую программу и написать аналогично функционирующую программу, которая не использовала if-else? Конечно, вы, вероятно, могли. Но это не значит, что это хорошая идея. ;)


GCC имеет statement expression, используя его, вы можете переписать if заявления эквивалентно ?: выражения:

if (<expression>)
  <statement1>
else
  <statement2>

"правка":void бросания служат двум целям. Подвыражения в ?: должен иметь тот же тип, и без void cast компилятор может печатать warning: statement with no effect.

(<expression>)? (void)({<statement1>}) : (void)({<statement2>});