Есть ли лучший способ преобразовать переменную в ‘const’ после присвоений?

#c

#c

Вопрос:

Я всегда использую const для защиты значений, которые не должны назначаться. В любом случае, в некоторых случаях мне может потребоваться инициализировать переменную, а затем использовать ее как const значение в той же функции. Например:

 void foo() {
  int flags;
  /* ... */
  if (condition1) 
      flags |= 1;
  /* .... */
  if (conditionX)
      flags |= Y;
  /* .... */
  // start using flags as a const value
  const flags; // <<= I want something like this.
  const int c_flags = flags; // <<= What I have to do. The naming is annoying.
  /* ... */
}
  

Есть ли какой-либо способ улучшить это? Это могут быть стили кодирования или расширенные языковые возможности.


От @Potatoswatter: для C в gcc / clang (в стиле gnu, скажем, -std = gnu11) можно использовать выражение оператора.

 foo() {
  const int flags = ({
    int f = 0;
    if (X) f |= Y;
    /* ... update f ... */
    f;
  });
  /* use the `const` flags */
}
  

Комментарии:

1. Вы можете использовать const_cast .

2. @Shravan40 Используется static_cast для добавления const . Используйте только const_cast для ее удаления , потому что это красный флаг.

3. Вы должны пометить C или C , а не оба, некоторые ответы здесь не могут быть применены к C.

4. Я думаю, что использование 2 версий одной и той же локальной переменной звучит как чрезмерное проектирование. Если вам сложно отслеживать, следует ли присваивать переменной или нет, ваша функция, вероятно, слишком велика.

5. Мой плохой. Это было для C. Поскольку все ответы идут на C , пусть так и будет…

Ответ №1:

Подумайте о создании функции, которая возвращает нужное вам значение

 const int flags = getFlags();
  

Или более объектно-ориентированный класс make a flags, который делает это в конструкторе.

 const Flags flags(condition1, ...);
  

Ответ №2:

В C вы можете инициализировать переменную, вызвав лямбда-выражение:

 const int flags = [amp;] {
    int flags = 0;

    if (condition1) 
        flags |= 1;
    ....
    if (conditionX)
        flags |= Y;

    return flags;
}();
  

На любом языке GCC и Clang (и другие компиляторы, совместимые с GCC) имеют аналогичную функцию в качестве расширения:

 const int flags = ({
    int flags = 0;

    if (condition1) 
        flags |= 1;
    ....
    if (conditionX)
        flags |= Y;

    flags;
});
  

Комментарии:

1. Мне это нравится. Обратите внимание, что это решение предназначено только для C .

2. @Nybble Если вас не волнует переносимость, GCC и Clang предлагают выражения операторов, которые работают аналогично в этом случае.

3. Большое спасибо. Выражение оператора — это именно то, что мне нужно.

Ответ №3:

Вы могли бы просто делегировать инициализацию вашей переменной функции и присвоить ее возвращаемое значение нужной const вам версии. Например:

 int bar() {
    int flags = 0;
    if (condition1) {
        flags |= 1;
    }
    // ...
    return flags;
}

void foo() {
    int const c_flags = bar();
    // ...
}
  

Это предполагает, что вы можете встроить condition1 , …, conditionX в bar . Если нет, вы всегда можете использовать функторы (лямбды) для проверки ваших предикатов и flags соответствующего обновления.

Ответ №4:

ИМО, это проблема стиля кодирования.

 int get_flags() {
  int flags;
  ....
  if (condition1) 
      flags |= 1;
  ....
  if (conditionX)
      flags |= Y;
  ....
  return flags;
}
void foo() {
  const int flags = get_flags();
  ....
}
  

Ответ №5:

Это звучит как не проблема… но если это реальная проблема, то правильный дизайн программы может легко ее решить:

 void foo() {
  int flags;

  flags = do_stuff_with(flags);

  take_decisions_based_on(flags);
}
  

где функции будут выглядеть примерно так:

 int do_stuff_with (int something);

void take_decisions_based_on (int something);
  

Вам даже не нужно применять корректность const, поскольку функции будут иметь дело только с локальными копиями переменной.

Ответ №6:

Как насчет использования троичного оператора:

 const int flags = condition1 ? 1 : (condition2 ? 2 : (conditionX ? Y : default_value))