2016-10-12 5 views
3

Я всегда использую const для защиты значений, которые не должны быть назначены. Во всяком случае, есть некоторые случаи, когда мне может понадобиться инициализировать переменную, а затем использовать ее как значение 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/лязгом (гну стиль, скажем, -std = gnu11), заявление может быть использовано выражение.

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

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

+3

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

+7

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

ответ

8

Рассмотрим сделать функцию, которая возвращает значение, которое вы хотите

const int flags = getFlags(); 

Или более объектно-ориентированный сделать класс флаги, что делает это в конструкторе.

const Flags flags(condition1, ...); 
1

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

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

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

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

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

    return flags; 
}(); 

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

const int flags = ({ 
    int flags = 0; 

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

    flags; 
}); 
+0

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

+1

@Nybble Если вы не заботитесь о переносимости, GCC и Clang предлагают [выражения операторов] (https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html), которые работают аналогично в этом случае. – Potatoswatter

+0

Большое спасибо. Выражение выражения - именно то, что мне нужно. – Nybble

2

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

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

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

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

0

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

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

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

0

Что об использовании троичной оператора:

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