2015-03-17 2 views
1

Я пишу небольшой арифметический класс с фиксированной точкой с параметрами шаблона для целых и дробных битов. При умножении двух небольших типов фиксированных точек результат должен быть более крупным фиксированным типом, чтобы фиксировать полный результат. Например. умножение двух чисел 8.8 с фиксированной точкой приводит к числу фиксированных точек 16.16.Как написать шаблон, приводящий к примитивному типу?

Мой класс выглядит следующим образом:

template<typename T, unsigned int bits, unsigned int frac> 
class FixedPoint { 
    public: 
    constexpr FixedPoint(int x = 0) : raw_(x << frac) { } 
    constexpr FixedPoint(double x) : raw_(x * (T(1) << frac)) { } 
    private: 
    T raw_; 
} 

Теперь проблема является параметром шаблона T, особенно для умножения, как тип результата отличается от типов аргументов и не может быть infered. Письмо a * b не работает.

То, что я хотел бы сделать, это заменить T с типом шаблона Int < бит + гидроразрыва > что является int8_t, int16_t, int32_t или int64_t в зависимости от количества битов общей требуемой.

Как написать такой тип? Я в порядке, ограничивая его ровно 8, 16, 32 или 64 бит.

+0

Почему вы подвергаете пользователя 'T' пользователю? Разве это не скрытая деталь реализации? Разве они не могут видеть только «бит» и «фрак»? –

+0

Да, они должны. Я просто не знал, как правильно выбрать тип для T. Это в основном вопрос. –

ответ

2

Самый простой (и, следовательно, лучше), чтобы использовать псевдоним

template<std::size_t bits> 
using integer_with_bits = 
    conditional_t<(bits<= 8), std::int8_t, 
    conditional_t<(bits<=16), std::int16_t, 
    conditional_t<(bits<=32), std::int32_t, 
    enable_if_t <(bits<=64), std::int64_t> > > >; 

, который во время компиляции эквивалентно времени выполнения ?:?:?:?: каскада. Затем integer_with_bits<3> - int8_t, а integer_with_bits<65> (и больше) создают ошибку времени компиляции. В приведенном выше примере я использовал вспомогательные средства

template<bool C, typename T> 
using enable_if_t = typename std::enable_if<C,T>::type; 

template<bool C, typename T1, typename T2> 
using conditional_t = typename std::conditional<C,T1,T2>::type; 
+0

Вспомогательные средства будут добавлены в 'std', если их там нет, поэтому проверьте свой' std', чтобы узнать, есть ли они. – Yakk

3

Вы можете использовать шаблон и специализацию:

template <std::size_t N> struct sizedType; 

template <> struct sizedType<8> { using type = std::uint8_t; }; 
template <> struct sizedType<16> { using type = std::uint16_t; }; 
template <> struct sizedType<32> { using type = std::uint32_t; }; 
template <> struct sizedType<64> { using type = std::uint64_t; }; 
+1

Если это не ясно - используйте 'typename sizeType :: type' вместо' T'. – jrok

2

Это не ограничивает его точно требуется биты. Вместо этого он находит самый маленький тот, который будет соответствовать, что многие биты:

template<class T>struct tag{using type=T;}; 
template<size_t bits_at_least> 
struct int_helper : int_helper<bits_at_least+1> {}; 

template<> struct int_helper<8 > : tag<int8_t > {}; 
template<> struct int_helper<16 > : tag<int16_t> {}; 
template<> struct int_helper<32 > : tag<int32_t> {}; 
template<> struct int_helper<64 > : tag<int64_t> {}; 
template<> struct int_helper<128> {}; // unsupported 

template<std::size_t bits> 
using integer = typename int_helper<bits>::type; 

затем integer<3> является int8_t.

integer<65> через integer<128> ошибка SFINAE (хороший и чистый), и integer<129> ошибка, которая будет спам сообщения об ошибках на вас (как он пытается создать экземпляр бесконечный каскад рекурсивных шаблонов).

Мы можем сделать эту компиляцию быстрее и генерировать лучшие ошибки, удалив это до 63 рекурсивных экземпляров и выполняя бит-скриптинг.

template<size_t n> 
using size = std::integral_constant<std::size_t, n>; 

template<size_t n> 
struct bits : size<bits<n/2>{}+1 > {}; 
template<> 
struct bits<0> : size<0> {}; 

template<class T>struct tag{using type=T;}; 

template<size_t bits_of_bits> 
struct int_helper_2 {}; 

// optional 0 bits of bits uses char: 
template<> struct int_helper_2<0> : tag<int8_t > {}; 
template<> struct int_helper_2<1> : tag<int8_t > {}; 
template<> struct int_helper_2<2> : tag<int8_t > {}; 
template<> struct int_helper_2<3> : tag<int8_t > {}; 
template<> struct int_helper_2<4> : tag<int16_t> {}; 
template<> struct int_helper_2<5> : tag<int32_t> {}; 
template<> struct int_helper_2<6> : tag<int64_t> {}; 

template<size_t bits_needed> 
struct int_helper : int_helper_2< bits<bits_needed>{} > {}; 

template<size_t bits_needed> 
using integer<bits_needed>=typename int_helper<bits_needed>::type; 

, который дает хорошие ошибки SFINAE всех размеров и должен скомпилироваться быстрее (менее рекурсия типа).

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