对于std::bitset
(禁止std)的自己实现,我使用了uint_fast32_t
,因为它在64位CPU上速度更快。审查意见是为了节省小型设备的空间,例如bitset <6>不应使用8个字节。如果您考虑在结构中对齐,则浪费会更大。
使用C ++ 11很好。我想优雅地选择:
作为我班上的存储类型:
template<size_t Size>
struct BitSet {
typedef <expression> StorageType;
// an array of that storage type...
};
我只能想到笨拙的帮助程序模板,但是C ++ 11中可能有些更优雅的东西。
编辑:澄清一下:uint_fast8_t
对于原始类来说很好,编译器可以选择任何快速的东西。想象大小== 1000000。但这在某些机器上是64位,并且在某些用例中,例如当大小很重要时。 Size == 4表示将浪费7个字节。
答案 0 :(得分:6)
鉴于可能选择的类型很少,我只是对条件进行硬编码:
using StorageType = std::conditional_t<Size <= 8, uint8_t,
std::conditional_t<Size <= 16, uint16_t,
std::conditional_t<Size <= 32, uint32_t, uint_fast32_t>>>;
或者,使用与@Caleth的答案类似的技巧:
using StorageType = std::tuple_element_t<(Size > 8) + (Size > 16) + (Size > 32),
std::tuple<uint8_t, uint16_t, uint32_t, uint_fast32_t>>;
答案 1 :(得分:3)
有助手
namespace detail {
template <int overload>
struct StorageType;
template <>
struct StorageType<0>{ using type = uint8_t; };
template <>
struct StorageType<1>{ using type = uint16_t; };
template <>
struct StorageType<2>{ using type = uint32_t; };
template <>
struct StorageType<3>{ using type = uint_fast32_t; };
}
然后我们可以对constexpr
个布尔值求和
template<size_t Size>
struct BitSet {
typedef typename detail::StorageType<(Size > 8) + (Size > 16) + (Size > 32)>::type StorageType;
// an array of that storage type...
};
答案 2 :(得分:1)
您可以将递归模板类与非类型模板参数一起用于位限制,并为相应的整数类型使用成员类型别名。
尽管您不需要自己编写这样的模板,Boost却涵盖了:boost::uint_t<N>::least
(如果您不是在寻找最小的但最快的,则为boost::uint_t<N>::fast
)。
P.S。如果您打算自己实现模板,并且想要最小整数类型(根据标题中的问题),则应使用std::uint_leastN_t
而不是uint_fastN_t
或uintN_t
。前者不一定是最小的类型,并且不能保证后者在所有系统上都存在。
此外,uint_fast32_t
不能保证能够表示多于32位,因此对于Size > 32
而言,这是一个较差的选择。我会推荐uint_least64_t
。
答案 3 :(得分:0)
冗长的解决方案,具有更少的魔力。参考:https://gcc.godbolt.org/z/P2AGZ8
#include<cstdint>
namespace helper { namespace internal {
enum class Size {
Uint8,
Uint16,
Uint32,
UintFast32,
};
constexpr Size get_size(int s) {
return (s <= 8 ) ? Size::Uint8:
(s <= 16) ? Size::Uint16:
(s <= 32) ? Size::Uint32: Size::UintFast32;
}
template<Size s>
struct FindTypeH;
template<>
struct FindTypeH<Size::Uint8> {
using Type = std::uint8_t;
};
template<>
struct FindTypeH<Size::Uint16> {
using Type = std::uint16_t;
};
template<>
struct FindTypeH<Size::Uint32> {
using Type = std::uint32_t;
};
template<>
struct FindTypeH<Size::UintFast32> {
using Type = std::uint_fast32_t;
};
}
template<int S>
struct FindType {
using Type = typename internal::FindTypeH<internal::get_size(S)>::Type;
};
}
template<int S>
struct Myclass {
using Type = typename helper::FindType<S>::Type;
};
答案 4 :(得分:0)
如果编译器支持,也可以使用constexpr if
-这可能是最容易阅读的。基于here中的代码的示例:
template<size_t S>
static constexpr auto _findStorageType() {
static_assert(S > 0, "Invalid storage size");
if constexpr (S <= sizeof(uint8_t) * CHAR_BIT) return uint8_t{};
else if constexpr (S <= sizeof(uint16_t) * CHAR_BIT) return uint16_t{};
else if constexpr (S <= sizeof(uint32_t) * CHAR_BIT) return uint32_t{};
else if constexpr (S <= sizeof(uint64_t) * CHAR_BIT) return uint64_t{};
else return __uint128_t{};
}