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

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

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

Ответы [ 8 ]

11 голосов
/ 30 ноября 2009

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

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

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

Все это операторы, которые состоят из одного выражения (приращение, присваивание, вызов функции, соответственно) и могут быть превращены в выражения в условном выражении.

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

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 не может быть создан и назначен по умолчанию.

4 голосов
/ 30 ноября 2009

На поверхности нет. Условный оператор является выражением (то есть имеет значение), а 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();

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

2 голосов
/ 30 ноября 2009

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

#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;
    }
}

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

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

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

1 голос
/ 30 ноября 2009

В принципе да:

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 и т. Д. Требуется оценка A не заканчивается TrueResult / FalseResult, но Вы используете эти исключения только для имитации if, проблем не будет.

1 голос
/ 30 ноября 2009
if( cond )
    break;
else
    a=b;

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

1 голос
/ 30 ноября 2009

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

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

1 голос
/ 30 ноября 2009

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

(condition) ? return x : return y;

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

if(condition) return x;
else return y;

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

0 голосов
/ 30 ноября 2009

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

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

РЕДАКТИРОВАТЬ: void броски служит двум целям. Подвыражения в ?: должны иметь один и тот же тип, и без преобразования void компилятор может вывести warning: statement with no effect.

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