Подтвердить что ты не робот

Каково надлежащее использование оператора запятой?

Я видел этот код:

if (cond) {
    perror("an error occurred"), exit(1);
}

Зачем вам это делать? Почему не просто:

if (cond) {
    perror("an error occurred");
    exit(1);
}
4b9b3361

Ответ 1

В вашем примере это вообще не имеет причины. Иногда полезно при написании как

if(cond)
  perror("an error occured"), exit(1) ;

- тогда вам не нужны нужны фигурные скобки. Но это приглашение к катастрофе.

Оператор запятой должен помещать два или более выражения в положение, в котором эта ссылка допускает только один. В вашем случае нет необходимости использовать его; в других случаях, например, в цикле while, может быть полезно:

while (a = b, c < d)
  ...

где фактическая "оценка" цикла while определяется только последним выражением.

Ответ 2

Легитимные случаи оператора запятой редки, но они существуют. Одним из примеров является то, что вы хотите, чтобы что-то произошло внутри условной оценки. Например:

std::wstring example;
auto it = example.begin();
while (it = std::find(it, example.end(), L'\\'), it != example.end())
{
    // Do something to each backslash in `example`
}

Он также может использоваться в тех местах, где вы можете разместить только одно выражение, но хотите, чтобы произошли две вещи. Например, следующий цикл увеличивает x и уменьшает y в третьем компоненте цикла for:

int x = 0;
int y = some_number;
for(; x < y; ++x, --y)
{
    // Do something which uses a converging x and y
}

Не ищите его использования, но если это уместно, не бойтесь его использовать и не бросайте за цикл, если увидите, что кто-то еще использует его. Если у вас есть две вещи, у которых нет причин не быть отдельными утверждениями, сделайте их отдельными операторами вместо использования оператора запятой.

Ответ 3

Оператор запятой позволяет группировать выражение, где ожидается.

Например, это может быть полезно в некоторых случаях:

// In a loop
while ( a--, a < d ) ...

Но в этом случае нет причин использовать его. Это будет путать... что это...

В вашем случае просто избегать фигурных скобок:

if(cond)
    perror("an error occured"), exit(1);

// =>
if (cond)
{
    perror("an error occured");
    exit(1);
}

Ссылка на описание запятой.

Ответ 4

Основное использование оператора запятой - обфускация; он позволяет делать два вещи, которые читатель только ожидает. Один из самых частых использует — добавление побочных эффектов к состоянию, попадает под это категория. Есть несколько случаев, которые могут считаться действительными, Однако:

Тот, который использовался, чтобы представить его в K & R: увеличивая два переменные в цикле for. В современном коде это может произойти в функции типа std::transform или std::copy, где выходной итератор одновременно увеличивается с входным итератором. (Чаще всего Конечно, эти функции будут содержать цикл while, приращения в отдельных операторах в конце цикла. В таком случаев нет смысла использовать запятую, а не два утверждения.)

Еще один случай, который приходит на ум, - это проверка данных входных параметров в списке инициализаторов:

MyClass::MyClass( T const& param )
    : member( (validate( param ), param) )
{
}

(Предполагается, что validate( param ) выдаст исключение, если что-то не так.) Это использование не особенно привлекательно, особенно так как ему нужны дополнительные круглые скобки, но альтернатив мало.

Наконец, я иногда видел соглашение:

ScopedLock( myMutex ), protectedFunction();

что позволяет избежать появления имени для ScopedLock. Рассказать правда, мне это не нравится, но я видел, как он использовался, и альтернатива добавления дополнительных брекетов, чтобы гарантировать, что ScopedLock разрушенный тоже не очень красивый.

Ответ 5

Это можно лучше понять, взяв несколько примеров:

Во-первых: Рассмотрим выражение:

   x = ++j;

Но на время, если нам нужно назначить временное значение отладки, тогда мы можем написать.

   x = DEBUG_VALUE, ++j; 

Второе:
Операторы Comma , часто используются в for() -loop, например:

for(i = 0, j = 10; i < N; j--, i++) 
 //      ^                   ^     here we can't use ;  

Третье:
Еще один пример (на самом деле можно найти интересное):

if (x = 16 / 4), if remainder is zero then print  x = x - 1;  
if (x = 16 / 5), if remainder is zero then print  x = x + 1;

Это также можно сделать за один шаг;

  if(x = n / d, n % d) // == x = n / d; if(n % d)
    printf("Remainder not zero, x + 1 = %d", (x + 1));
  else
    printf("Remainder is zero,  x - 1 = %d", (x - 1));

PS: Также может быть интересно узнать, что иногда бывает катастрофично использовать оператор ,. Например, в вопросе использование Strtok, код не работает, по ошибке OP забыл написать имя функции и вместо записи tokens = strtok(NULL, ",'"); написал tokens = (NULL, ",'"); и он не получал ошибку компиляции - но его действительное выражение, которое tokens = ",'"; вызвало бесконечный цикл в его программе.

Ответ 6

В вашем случае оператор запятой бесполезен, поскольку его можно было бы использовать, чтобы избежать фигурных скобок, но это не так, поскольку писатель уже поставил их. Поэтому он бесполезен и может запутать.

Ответ 7

По-видимому, мало практических применений оператора,().

Bjarne Stroustrup, The Design and Evolution of С++

Большинство часто используемых запятой можно найти в статье wikipedia Comma_operator#Uses.

Одно интересное использование, которое я обнаружил при использовании boost:: assign, где он разумно перегрузил оператора, чтобы заставить его вести себя как запятыми список значений, которые могут быть перенесены в конец векторного объекта

#include <boost/assign/std/vector.hpp> // for 'operator+=()'
using namespace std;
using namespace boost::assign; // bring 'operator+=()' into scope

{
    vector<int> values;  
    values += 1,2,3,4,5,6,7,8,9; // insert values at the end of the container
}

К сожалению, вышеприведенное использование, которое было популярно для прототипирования, теперь будет выглядеть архаичным, если компиляторы начнут поддерживать Uniform Initialization

Таким образом, мы вернемся к

По-видимому, мало практических применений оператора,().

Bjarne Stroustrup, The Design and Evolution of С++

Ответ 8

boost::assign сильно перегружает запятую для достижения такого синтаксиса:

vector<int> v; 
v += 1,2,3,4,5,6,7,8,9;

Ответ 9

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

Например:

a<b?(x=5,b=6,d=i):exit(1);