C ++数组类型取决于模板类型

时间:2017-09-13 20:35:36

标签: c++ c++11 templates

我有一个具有整数模板参数N的类。

template<unsigned int N>
class test {
}

现在我希望std::vector具有尽可能小的整数类型来保存N位。

E.g。

class test<8> {
    std::vector<uint8_t> data;
}

class test<9> {
    std::vector<uint16_t> data;
}

class test<10> {
    std::vector<uint16_t> data;
}
...

对于N=1N=64,还有更好的方法吗?

2 个答案:

答案 0 :(得分:3)

使用条件怎么样?

#include <vector>
#include <cstdint>
#include <iostream>
#include <type_traits>

template <std::size_t N>
struct foo
 {
   static_assert( N < 65U, "foo 64 limit");

   using vType = typename std::conditional<
      (N < 9U), std::uint8_t,
        typename std::conditional< (N < 17U), std::uint16_t,
           typename std::conditional< (N < 33U), std::uint32_t, std::uint64_t
   >::type>::type>::type;

   std::vector<vType> data;
 };

int main()
 {
   static_assert( 1U == sizeof(foo<1>::vType), "!");
   static_assert( 1U == sizeof(foo<8>::vType), "!");
   static_assert( 2U == sizeof(foo<9>::vType), "!");
   static_assert( 2U == sizeof(foo<16>::vType), "!");
   static_assert( 4U == sizeof(foo<17>::vType), "!");
   static_assert( 4U == sizeof(foo<32>::vType), "!");
   static_assert( 8U == sizeof(foo<33>::vType), "!");
   static_assert( 8U == sizeof(foo<64>::vType), "!");

   // foo<65> f65; compilation error
 }

或者,以更优雅的方式(恕我直言),您可以定义一个类型特征(在下面的示例中为selectTypeByDim),用于选择列表中的第一个有用类型

#include <tuple>
#include <vector>
#include <cstdint>
#include <climits>
#include <type_traits>

template <std::size_t N, typename T,
   bool = (N <= sizeof(typename std::tuple_element<0U, T>::type)*CHAR_BIT)>
struct stbdH;

template <std::size_t N, typename T0, typename ... Ts>
struct stbdH<N, std::tuple<T0, Ts...>, true>
 { using type = T0; };

template <std::size_t N, typename T0, typename ... Ts>
struct stbdH<N, std::tuple<T0, Ts...>, false>
 { using type = typename stbdH<N, std::tuple<Ts...>>::type; };

template <std::size_t N, typename ... Ts>
struct selectTypeByDim : stbdH<N, std::tuple<Ts...>>
 { };

template <std::size_t N>
struct foo
 {
   static_assert( N < 65U, "foo 64 limit");

   using vType = typename selectTypeByDim<N,
         std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t>::type;

   std::vector<vType> data;
 };

int main()
 {
   static_assert( 1U == sizeof(foo<1U>::vType), "!");
   static_assert( 1U == sizeof(foo<CHAR_BIT>::vType), "!");
   static_assert( 2U == sizeof(foo<CHAR_BIT+1U>::vType), "!");
   static_assert( 2U == sizeof(foo<(CHAR_BIT<<1)>::vType), "!");
   static_assert( 4U == sizeof(foo<(CHAR_BIT<<1)+1U>::vType), "!");
   static_assert( 4U == sizeof(foo<(CHAR_BIT<<2)>::vType), "!");
   static_assert( 8U == sizeof(foo<(CHAR_BIT<<2)+1U>::vType), "!");
   static_assert( 8U == sizeof(foo<(CHAR_BIT<<3)>::vType), "!");

   //foo<(CHAR_BIT<<3)+1U> f65; compilation error
 }

答案 1 :(得分:1)

根据您对问题的评论,您实际上并不需要内置类型。任何可复制的可移动对象都可以放入向量中。

如果要对数据进行排序,我建议使用自定义{{std::bitset<2*N>std::array<std::byte, (2*N+7)/8>(或std::array<std::byte, (2*N+CHAR_BIT-1)/CHAR_BIT>,如果您在一个奇怪的系统上运行) 1}}用于排序。如果你有任何其他用途(你可能会这样做),我会建议一个自定义类,其中一个作为其底层存储;这使您可以添加更多功能,例如获取特定的基础。

在大多数系统上,如果Compare是32或64的倍数(取决于实现),std::bitset将没有开销,但这不能保证。字节数组的开销通常不会超过C ++所需的开销。如果需要,这两个都可以扩展到超过64位,并且字节数组将具有最小的空间开销,甚至比使用整数类型更少,因为它不会强制大小为2的幂。在其中任何一个上添加自定义类都不会产生任何开销。

(如果您使用的是C ++ 14或更低版本,则可以使用Nchar代替uint8_t; byte更接近您想要的但是仅在C ++中可用17.如果您现在正在使用C ++ 14但可能会切换,我建议您在代码中放置byte,然后在升级时将其切换出来)