Является ли это разумным использованием тернарного оператора?
Есть ли какие-либо проблемы с пониманием/ремонтопригодностью, возникающие из-за кода типа
inVar1 == 0 ? NULL : v.push_back(inVar1);
inVar2 == 0 ? NULL : v.push_back(inVar2);
и т.д.
Возможно, запутанная идея заключается в использовании тройного оператора для потока программы, а не для присваивания переменной, что является обычным объяснением.
Я не видел стандартов кодирования на работе, которые обращаются к этому использованию, поэтому, когда мне удобно это делать, я хотел бы узнать, есть ли повода для этого.
Ответы
Ответ 1
Я думаю, что это сбивает с толку и гораздо труднее читать, чем просто набирать текст;
if (inVar != 0)
v.push_back(inVar);
Мне пришлось несколько раз сканировать ваш пример, чтобы выяснить, какой результат будет с какой-либо определенностью. Я даже предпочитаю однострочный оператор if() {}, чем ваш пример, - и я ненавижу однострочные операторы if:)
Ответ 2
Тернарный оператор предназначен для возврата значения.
IMO, он не должен мутировать состояние, и нужно использовать возвращаемое значение.
В другом случае используйте инструкции if. Если утверждения предназначены для выполнения блоков кода.
Ответ 3
Тернар - это хорошо, и я обычно продвигаю его.
То, что вы здесь делаете, тем не менее подрывает его доверие. Это короче, да, но это бесполезно сложно.
Ответ 4
Я думаю, этого следует избегать. Вы можете использовать оператор 1-строчной if на своем месте.
if(inVar1 != 0) v.push_back(inVar1);
Ответ 5
Составители в эти дни сделают так быстро, как тройной оператор.
Ваша цель должна заключаться в том, как легко это сделать для другого разработчика программного обеспечения.
Я голосую за
if ( inVar != 0 )
{
v.push_back( inVar );
}
почему скобки... потому что в один прекрасный день вам захочется положить что-то еще, и скобки сделаны для вас. Большинство редакторов в эти дни все равно поставят их.
Ответ 6
Ваше использование троичного оператора ничего не дает вам, и вы ухудшаете читаемость кодов.
Так как тернарный оператор возвращает значение, которое вы не используете, это нечетный код. Использование if
гораздо более понятно в случае, таком как ваш.
Ответ 7
Как указано в комментариях, этот недействителен С++. GCC, например, выдает ошибку в этом коде:
error: `(&v)->std::vector<_Tp, _Alloc>::push_back [with _Tp = int, _Alloc =
std::allocator<int>](((const int&)((const int*)(&inVar1))))' has type `void'
and is not a throw-expression
Тем не менее, это можно обойти путем кастинга:
inVar1 == 0 ? (void)0 : v.push_back(inVar1);
inVar2 == 0 ? (void)0 : v.push_back(inVar2);
Но какой ценой? И с какой целью?
Не похоже, что использование тернарного оператора здесь более кратким, чем if-statement в этой ситуации:
inVar1 == 0 ? NULL : v.push_back(inVar1);
if(inVar1 != 0) v.push_back(inVar1);
Ответ 8
Хотя на практике я согласен с чувствами тех, кто препятствует этому типу письма (при чтении вам нужно сделать дополнительную работу для сканирования выражения для его побочных эффектов), я бы хотел предложить
!inVar1 ?: v.push_back(inVar1);
!inVar2 ?: v.push_back(inVar2);
... если вы собираетесь неясным, то есть. GCC позволяет x ?: y
вместо x ? x : y
.: -)
Ответ 9
Я использую тернарный оператор, когда мне нужно вызвать некоторую функцию с условными аргументами - в этом случае лучше, чем if
.
Для сравнения:
printf("%s while executing SQL: %s",
is_sql_err() ? "Error" : "Warning", sql_msg());
с
if (is_sql_err())
printf("Error while executing SQL: %s", sql_msg());
else
printf("Warning while executing SQL: %s", sql_msg());
Я считаю, что первое более привлекательно. И он соответствует принципу DRY, в отличие от последнего - вам не нужно писать две почти одинаковые строки.
Ответ 10
Я думаю, вам будет лучше служить в правильной структуре. Я даже предпочитаю всегда иметь фигурные скобки с моими if-структурами, в случае, если мне придется добавлять строки позже к условному исполнению.
if (inVar != 0) {
v.push_back(inVar);
}
Ответ 11
Я думаю, что иногда тройка является необходимым злом в списках инициализаций для конструкторов. Я использую их в основном для конструкторов, где я хочу выделить память и установить некоторый указатель, чтобы указать на нее перед телом конструктора.
В примере предположим, что у вас есть целочисленный класс хранения, который вы хотели бы взять в качестве входного вектора, но внутреннее представление представляет собой массив:
class foo
{
public:
foo(std::vector<int> input);
private:
int* array;
unsigned int size;
};
foo:foo(std::vector<int> input):size(input.size()), array( (input.size()==0)?
NULL : new int[input.size])
{
//code to copy elements and do other start up goes here
}
Вот как я использую тернарный оператор. Я не думаю, что это так же запутывает, как некоторые люди, но я думаю, что нужно ограничивать, насколько они его используют.
Ответ 12
Большинство замученных тройников (как это для аллитерации?), я вижу, это просто попытки поставить логику, которая действительно принадлежит в выражении if в месте, где утверждение if не принадлежит или не может идти.
Например:
if (inVar1 != 0)
v.push_back(inVar1);
if (inVar2 != 0)
v.push_back(inVar2);
работает, полагая, что v.push_back недействителен, но что, если он возвращает значение, которое нужно передать другой функции? В этом случае он должен будет выглядеть примерно так:
SomeType st;
if (inVar1 != 0)
st = v.push_back(inVar1);
else if (inVar2 != 0)
st = v.push_back(inVar2);
SomeFunc(st);
Но это больше, чтобы переварить такой простой кусок кода. Мое решение: определить другую функцию.
SomeType GetST(V v, int inVar1, int inVar2){
if (inVar1 != 0)
return v.push_back(inVar1);
if (inVar2 != 0)
return v.push_back(inVar2);
}
//elsewhere
SomeFunc(GetST(V v, inVar1, inVar2));
Во всяком случае, дело в том, что если у вас есть какая-то логика, которая слишком подверглась пыткам за тройной язык, но будет загромождать ваш код, если он помещается в оператор if, поместите его в другое место!
Ответ 13
inVar1 != 0 || v.push_back(inVar1);
inVar2 != 0 || v.push_back(inVar2);
общий шаблон, найденный на таких языках, как Perl.
Ответ 14
Если у вас есть несколько вызовов метода в одном или обоих из десятичных аргументов, то это неправильно. Все строки кода, независимо от того, какое утверждение должно быть коротким и простым, в идеале не усугубляются.
Ответ 15
Правильное, если утверждение более читаемо, как упомянули другие. Кроме того, когда вы переходите через свой код с помощью отладчика, вы не сможете легко увидеть, какая ветка if выполняется, когда все находится в одной строке или вы используете тройное выражение:
if (cond) doIt();
cond ? noop() : doIt();
В то время как следующее намного лучше, чтобы пройти (у вас есть скобки или нет):
if (cond) {
doIt();
}
Ответ 16
Как уже упоминалось, он не короче или яснее, чем оператор 1 строки if. Тем не менее, это тоже не так - и на самом деле это не так сложно. Если вы знаете тройного оператора, это довольно очевидно, что происходит.
В конце концов, я не думаю, что у кого-то была бы проблема, если бы она была назначена переменной (даже если она тоже была мутирующей):
var2 = inVar1 == 0 ? NULL : v.push_back(inVar1);
Тот факт, что тернарный оператор всегда возвращает значение - ИМО - не имеет значения. Конечно, нет необходимости использовать все возвращаемые значения... ведь назначение присваивает значение.
При этом я заменил бы его выражением if, если бы я натолкнул его на ветвь NULL.
Но если он заменил оператор 3 строки:
if (inVar == 0) {
v.doThingOne(1);
} else {
v.doThingTwo(2);
}
с:
invar1 == 0 ? v.doThingOne(1) : v.doThingTwo(2);
Я мог бы оставить это... в зависимости от моего настроения.;)