Ответ 1
Я использовал этот тип конструкции много раз. Пока он отлично отформатирован (т.е. Не все на одной строке, что делает его нечитаемым), я не вижу проблемы с ним.
Я только что увидел этот блок кода в статье Wikipedia об условных операторах:
Vehicle new_vehicle = arg == 'B' ? bus :
arg == 'A' ? airplane :
arg == 'T' ? train :
arg == 'C' ? car :
arg == 'H' ? horse :
feet;
Я немного изменил код, но идея такая же. Вы нашли бы это использование условного оператора приемлемым? Это гораздо более кратким, чем конструкция if
- else
, и с помощью коммутатора определенно откроется целый новый набор возможностей для ошибок (проваливается кто-нибудь?). Кроме того, if
- else
и switch
не могут использоваться как значения R, поэтому вам нужно сначала создать переменную, инициализировать ее и затем назначить по мере необходимости.
Я действительно так люблю, но мне интересно, что думают другие.
Но форматирование имеет важное значение.
EDIT: Мне все еще нравится это. Но я понимаю тех, кто говорит, что для этого было сделано выражение switch
. Хорошо, может быть, так. Но что, если условия являются вызовами функций, возвращающими bool
? Или миллион других вещей, которые вы не можете включить.
Вы меняете любовников, которые действительно пытаются убедить меня, что огромная цепочка if
- else
лучше? Да, программисты, которые не знают, как использовать условный оператор, не поймут этого. Они должны научиться использовать его. Это не тайное.
Я использовал этот тип конструкции много раз. Пока он отлично отформатирован (т.е. Не все на одной строке, что делает его нечитаемым), я не вижу проблемы с ним.
Я бы использовал переключатель, потому что это то, для чего он был предназначен. Да, существует риск ошибок при сбое, но этот вложенный-условный блок имеет гораздо более высокий риск того, что другие программисты будут неправильно поняты.
Это отличный пример использования условного оператора. Я использую его таким образом все время в С++, Java и Perl.
В нем нет ничего плохого, он связывает цель операции наиболее кратким и понятным образом.
Замена с помощью if else или для построения коммутатора требует, чтобы фрагмент
"new_vehicle = "
повторяется в каждом экземпляре, что требует, чтобы читатель читал каждый повторяющийся экземпляр, чтобы убедиться, что он на самом деле одинаковый во всех случаях.
Мне это нравится. Это похоже на лестницу if-else-if, только более кратким.
Там много пробелов вокруг символьных констант, что делает его немного трудным для чтения. Я бы скорректировал сравнения: (и, возможно, переместите последнее значение в строке.)
Vehicle new_vehicle = (arg == 'B') ? bus :
(arg == 'A') ? airplane :
(arg == 'T') ? train :
(arg == 'C') ? car :
(arg == 'H') ? horse :
feet;
Теперь он выглядит великолепно.
Условная версия оператора чиста, проста и сразу же очевидна для любого, кто знает C или С++, что происходит. Другим достоинством является то, что он немедленно возвращает значение, что означает, что его можно поместить в инициализацию (например, этот пример).
Оператор переключения будет более неуклюжим. Это потребует, чтобы переменная была объявлена и затем инициализирована, обычно это плохая идея, если ее можно избежать. Это потребует больше ввода текста, и у вас будет больше мест для ошибок. Это будет не так ясно, так как нужно будет посмотреть на каждый случай, чтобы увидеть, что он сказал что-то вроде new_vehicle = foo; break;
.
Если вы собираетесь делать это только здесь, то наличие условной версии в порядке, это хорошо, поскольку это сразу показывает, что происходит. Если это произойдет не один раз, подумайте о том, чтобы включить его в функцию, так что есть только одно место для обновления, если что-то изменится (например, "R" для перевозки или "L" для вертолета).
Коммутатор является более четким и, возможно, намного более эффективным. Если бы я видел такой код при просмотре кода, я был бы обеспокоен. Кроме того, это "условный оператор" - это экземпляр (хотя в настоящее время единственный в C и С++) тернарного оператора.
Чисто стилистический выбор. Для небольших наборов данных, таких как вы здесь, тогда, пока ваша команда разработчиков не выбрасывается такой штукой, то это прекрасно в моей книге.
Vehicle new_vehicle = getVehicleByType(arg);
Vehicle getVehicleByType(char arg){
if (arg == 'B') return bus;
if (arg == 'A') return airplane;
if (arg == 'C') return car;
if (arg == 'T') return train;
if (arg == 'H') return horse;
return feet;
}
Мне нравится это лучше. Вложенные условные умны, но я думаю, что это почти так же кратким и с меньшей вероятностью путает будущего читателя. Извините, если синтаксис выключен, в настоящее время я не делаю много C.
EDIT: Исправлено упущение типа возвращаемого типа в комментариях. ТНХ!
EDIT: Я, кстати, не ужасаюсь вашей версией. Я не воскликнул WTF или OMG, когда увидел это. Я просто предпочитаю мой немного больше:)
Мне это не особенно нравится.
Он ничего не покупает или не делает ничего более ясного, и это довольно нестандартное использование оператора.
Похоже, основное преимущество в том, что оно несколько умное. Я избегаю умных, если нет достаточно хорошей (внешней) причины, чтобы быть умным.
Я бы наклонился к команде switch, потому что компилятор поймает повторяющиеся случаи. Возможно, это не проблема в этом примере, но если список становится очень длинным и обрабатывается несколькими разными людьми, легко добавить дубликат и не осознавать его.
Прочтите раздел С++ статьи в Википедии более осторожно. Он явно перечисляет некоторые ситуации, когда использование оператора ?:
является единственной опцией и не может быть заменено на if/else
или switch
.
С другой стороны, я бы не использовал его только потому, что он выглядит красивее.
Я никогда раньше не видел ничего подобного. Хотя он умный и хорошо отформатированный, это кажется прекрасной возможностью использовать словарь/хэш-таблицу (предполагая, что Vehicle
- это перечисление, которое неясно).
Несколько человек уже упомянули о возможности использования типа std::map
или другого ассоциативного массива для выполнения задания. Пока вы делаете это только одно место (или несколько мест), вы можете вместо этого использовать обычный массив или вектор:
Vehicle vehicles[CHAR_MAX];
// Initialization
std::fill_n(vehicles, CHAR_MAX, feet);
vehicles['A'] = airplane;
vehicles['B'] = bus;
vehicles['C'] = car;
vehicles['H'] = horse;
vehicles['T'] = train;
// Use
Vehicle new_vehicle = vehicles[arg];
В зависимости от того, как таблицы, которые вам нужны/используют (которые хранят один и тот же тип объекта), и размер содержащихся объектов (в данном случае это автомобиль), могут быть вполне разумной альтернативой std::map
. Если вы создаете много таблиц или каждый объект действительно большой, std::map
становится более разумной альтернативой.
Когда вы используете std::map
(или unordered_map
и т.д.), вы используете больше кода для сохранения данных. Это делает обратное - но пока Транспортное средство мало (скажем, 4 байта), одна таблица, подобная выше, обычно занимает примерно половину килобайта. Трудно догадаться, насколько большой код для std::map
будет для конкретного компилятора, но кажется вероятным, что он обычно будет больше половины килобайта, поэтому, если вы создаете только одну таблицу, std::map
может быть чистым убытком.
Конечно, если вы знаете, что используете только буквы в качестве ввода, вы можете немного уменьшить размер таблицы:
template <class T>
class letter_table {
static const int range = 'Z' - 'A';
T table[range];
public:
// ...
T operator[](int index) {
index -= 'A';
assert(index<range);
return table[index];
}
};
В примерном случае это даст таблицу около 100 байт - вы можете создать довольно справедливое количество 100-байтных таблиц в пространстве std::map
, которое обычно занимает.
Плюс: Тройная последовательность более гибкая и может использоваться для предотвращения ограничений switch
, вы можете использовать другие операторы (например, < =, > =) или любые другие тесты, включая, например, сравнение строк.
x = IsEven(arg) ? 0 :
(arg < 0) ? -1 : 1; // or whatever
Кроме того, если коммутатор является узким местом производительности, и у вас есть неравномерность вероятностей, вы можете принудительно выполнить наиболее вероятные тесты (из-за не оцененной гарантии для выбранного пути).
So-So
В отличие от оператора switch, порядок важен (если вы не придерживаетесь ==
). Это может быть преимуществом, но в остальном аналогично переключателю, который может вводить в заблуждение, когда сопровождающий незнаком с концепцией или спешит.
Многие разработчики могут уклониться, потому что они не уверены в деталях (какие условия будут оцениваться, является ли скорость операторов достаточной?). Однако, если ваш пул разработчиков не поймет хорошо представленный пример, у вас могут быть проблемы, которые не могут быть решены путем запрета троичных операторов.
минус
Это не так часто, как switch
, поэтому оптимизатор может не относиться к нему одинаково. Оптимизаторы знают, как выбрать наиболее подходящую реализацию для коммутатора (таблица, двоичный поиск, последовательность сравнения или любая комбинация этого). Оптимизаторы не могут обновить порядок wevaluaiton, и они вряд ли будут поддерживать поиск таблицы здесь.
Требуется, чтобы хорошее форматирование было легко узнаваемым (выравнивание "?" и ":" ) - отстой, когда вы используете вкладки.
Мне нравится его точность и лаконичность, близкие к математическим обозначениям. Однако это может быть использовано и против него. Вероятно, это бровь в обзорах кода, потому что он менее распространен и более хрупкий.
Просто для сравнения, в С++ 0x вы можете иметь выражение без использования условного оператора или внелинейной функции:
Vehicle new_vehicle = [&]() -> Vehicle {
if (arg == 'B') return bus;
if (arg == 'A') return airplane;
if (arg == 'T') return train;
if (arg == 'C') return car;
if (arg == 'H') return horse;
return feet;
}();
Однако не лучше.
На мой взгляд, то, что вы сделали, приемлемо из-за простоты примера. Если вы делали больше вещей в каждом случае, этот тип конструкции мог бы быстро запутаться. По этой причине я предпочел бы переключатель или даже вложенный, если тогда elses (если их не так много), отформатирован следующим образом:
if (A) {
//Do A stuff
}
else if (B) {
//Do B stuff
}
else if (C) {
//Do C stuff
}
else {
//Do default stuff
}
Это о читаемости кода, который поддается ремонтопригодности кода. Я никогда не был большим поклонником условного оператора, потому что мне не нравится видеть несколько выражений в одной строке. Условные операторы могут быть трудными для выполнения при однократном выполнении кода в отладчике. Чем проще код, тем легче сконцентрироваться на том, что делает код.
Как насчет:
enum Vehicle { bus = 'B', airplane = 'A', train, car = 'C', horse = 'H', feet = 'F' };
...
new_vehicle = arg;
:-), между прочим.
Я думаю, что он полезен для кого-то, кто его кодирует, но будет трудно понять для ревиуэра,
"ХРАНИТЕ ЕГО ПРОСТОЙ БУДДИ"
Многие из нас привыкли к IIF-функциям в различных инструментах отчетности или If-функции в Excel, где нам в основном нужно использовать менее понятный Iif (arg = "B"; "Bus"; Iif (arg = "А"; Самолет, "нога" )). Мне нравится ваш образец по сравнению с этим:) Я лично бы использовал if-elses, но у меня не было бы проблем с вашим образцом.