Является ли это разумным использованием тернарного оператора?

Есть ли какие-либо проблемы с пониманием/ремонтопригодностью, возникающие из-за кода типа

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);

Я мог бы оставить это... в зависимости от моего настроения.;)