Как мой код может отличить константу времени компиляции от переменной?

Вот мой проблема. У меня есть макрос BINARY_FLAG :

#define BINARY_FLAG( n ) ( static_cast( 1 << ( n ) ) )

Который может использоваться либо так («постоянный» сценарий):

static const SomeConstant = BINARY_FLAG( 5 );

, либо так («переменный» сценарий):

for( int i = 0; i < 10; i++ ) {
    DWORD flag = BINARY_FLAG( i );
    // do something with the value
}

Этот макрос не является надежным вообще - здесь можно передать -1 или 34 , и будет самое большее предупреждение, но поведение будет неопределенным. Я хотел бы сделать его более надежным.

Для постоянного сценария я мог бы использовать шаблон:

template class BinaryFlag {
staticAssert( 0 <= Shift && Shift < sizeof( DWORD) * CHAR_BIT );
public:
static const DWORD FlagValue = static_cast( 1 << Shift );
};
#define BINARY_FLAG( n ) CBinaryFlag::FlagValue

, но он не пойдет для «переменного» сценария - мне понадобится утверждение времени выполнения:

inline DWORD ProduceBinaryFlag( int shift )
{
    assert( 0 <= shift && shift < sizeof( DWORD) * CHAR_BIT );
    return static_cast( 1 << shift );
}
#define BINARY_FLAG( n ) ProduceBinaryFlag(n)

Последний вариант хорош, но не требует проверок во время компиляции. Конечно, мне бы хотелось, чтобы по возможности выполнялась проверка во время компиляции, а в противном случае - проверка во время выполнения. Я всегда хочу как можно меньше накладных расходов во время выполнения, поэтому я не хочу вызова функции (которая, возможно, не будет встроена), когда возможна проверка во время компиляции.

Я видел этот вопрос , но не похоже, что это одна и та же проблема.

Есть ли какая-нибудь конструкция, которая позволяла бы переключаться между ними в зависимости от того, является ли выражение, переданное как номер флага, константой времени компиляции или переменной ?

5
задан Community 23 May 2017 в 12:07
поделиться