2012-03-15 4 views
2

Мне нужно замаскировать некоторые ведущие биты значения. Если значение без знака, я могу утверждать (гарантировать), что какое-то произвольное число ведущих битов не задано, то есть гарантированно ограниченное значение.Тестирование подписи параметра шаблона

Если он подписан, мне нужно замаскировать ведущие биты (превращение значения в некоторую непереносимую кучу бит, да, я знаю об этом :-)). Я хотел бы сохранить операцию маскировки, если значение не указано.

Так что я в основном имею

template<typename T, some more template parameters> 
class { 
    unsigned transform(T value) { 
     ... 
     if (isSigned(T)) { 
      value &= mask; 
     } 
     ... 
    } 
} 

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

Конечно, я мог бы добавить еще один параметр шаблона ...

ответ

5

Да. Вы должны использовать частичную специализацию:

template <bool> struct impl { static void foo(); }; 
template <> struct impl<true> { static void foo(); }; 

template <typename T> struct Foo 
{ 
    void do_magic(T const &) 
    { 
     impl<std::is_signed<T>::value>(); 
     // ... 
    } 
}; 

Вы можете использовать класс готовые is_signed черты от <type_traits>, а не прокатки самостоятельно.

+0

Собственно, компилятор полностью способен оптимизировать мертвый код. Но это может вызвать предупреждение ... –

+1

@ KonradRudolph: Это деталь. OP может захотеть написать код, который имеет смысл только в одном из двух случаев, и оператор 'if' требует, чтобы вы указали правильный код, даже если он никогда не используется. Шаблоны не имеют этого ограничения. –

+0

Спасибо, я поеду за этим. Главное, чего не хватало: 'std :: is_signed ' (или 'numeric_limits :: is_signed' или даже' T (-1) hirschhornsalz

3
if (T(-1) < T(0)) 

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

Что-то вроде:

template <typename T, bool is_signed> 
inline void apply_mask_helper(T& value) { value &= mask; } 

template <typename T> 
inline void apply_mask_helper<T, false>(T&) { } 

template <typename T> 
inline void apply_mask(T& value) { apply_mask_helper<T, T(-1) < T(0)>(value); } 
+0

Я думал, что у OP уже была проверка времени на компиляцию и просто нужна статическая версия условного ... –

+0

Я поеду за этим и посмотрю на сгенерированный код, обычно gcc обрабатывает это довольно приятное :-) – hirschhornsalz

+0

@ Kerrek Статический условный? AFAIK это может работать только с тернарным оператором, потому что 'if' оценивается только во время выполнения? – hirschhornsalz

2

Использование numeric_limits из заголовка limits:

if(numeric_limits<T>::is_signed) { … } 

Как Kerrek сказал, я бы с частичной специализации. В противном случае компилятор может пожаловаться на то, что значение условия известно во время компиляции.

Смежные вопросы