如何为多个整数值范围专门化C ++模板?

时间:2018-01-09 16:47:58

标签: c++ templates conditional template-specialization

我试图创建一个用于处理比特流的模板类。我希望模板中声明的基础整数类型可以解析为uint8_tuint16_tuint32_tuint64_t,具体取决于模板参数(int,位数)。我找到了关于这个主题的两个答案(How can I specialize a C++ template for a range of integer values?Integer range based template specialisation)并实现了以下代码:

template<int BITS>
class MyClass {
   typedef typename
      std::conditional< BITS <= 8,  uint8_t,
      std::conditional< BITS <= 16, uint16_t,
      std::conditional< BITS <= 32, uint32_t, uint64_t > > >::type
         int_type;
    ...
}

在我的程序中,我实例化MyClass<32>,但在编译时,我收到以下错误:

no known conversion for argument 1 from ‘uint32_t {aka unsigned int}’ to ‘MyClass<32>::int_type {aka std::conditional<false, short unsigned int, std::conditional<true, unsigned int, long unsigned int> >}’

如果我实例化MyClass<8>,那么一切正常。所以看起来只有std::conditional的第一级实际上是扩展的。

知道如何正确地做到这一点吗?

编辑:我之前没有说过这个,但我正在寻找一个适用于任何比特大小实例化的解决方案(只要它能够实现)最多64位)。所以我希望MyClass<27>能够正常工作(选择uint32_t)。

3 个答案:

答案 0 :(得分:6)

最简单的越好:

template<unsigned nbits> struct uint {};

template<> struct uint<8> { using type = uint8_t; };
template<> struct uint<16> { using type = uint16_t; };
template<> struct uint<32> { using type = uint32_t; };
template<> struct uint<64> { using type = uint64_t; };

template<int nbits>
struct MyClass { using int_type = typename uint<(nbits/8)*8>::type; };

答案 1 :(得分:2)

回答编辑并使原始代码正常工作。

template<int BITS>
class MyClass {
   using int_type =
      typename std::conditional< BITS <= 8,  uint8_t,
      typename std::conditional< BITS <= 16, uint16_t,
      typename std::conditional< BITS <= 32, uint32_t, uint64_t >::type >::type >::type;
   public:
   int_type i;
};

答案 2 :(得分:0)

问题的解决方案已在the answer by @super中提供。

了解错误信息对我很有帮助。

您已将int_type定义为:

typedef typename
  std::conditional< BITS <= 8,  uint8_t,
  std::conditional< BITS <= 16, uint16_t,
  std::conditional< BITS <= 32, uint32_t, uint64_t > > >::type
     int_type;

以来,BITS <= 8正常运行
  std::conditional< BITS <= 16, uint16_t,
  std::conditional< BITS <= 32, uint32_t, uint64_t > >

部分基本上被忽略了。

我们假设您使用MyClass<16>。然后,忽略uint8_t。你对int_type的所作所为:

  std::conditional< BITS <= 16, uint16_t,
  std::conditional< BITS <= 32, uint32_t, uint64_t > >

可以简化为:

  std::conditional< true, uint16_t,
  std::conditional< true, uint32_t, uint64_t > >

不幸的是,这是您在不使用std::conditional<...>::type的情况下获得的类型。

我们假设您使用MyClass<32>。那么你对int_type所拥有的是:

  std::conditional< BITS <= 16, uint16_t,
  std::conditional< BITS <= 32, uint32_t, uint64_t > >

可以简化为:

  std::conditional< false, uint16_t,
  std::conditional< true, uint32_t, uint64_t > >

这是你得到的类型。

您可以通过打印相应type_info个对象的名称来了解这些类型。

示例程序:

#include <iostream>
#include <typeinfo>
#include <type_traits>
#include <cstdint>

template<int BITS>
struct MyClass
{
   typedef typename
      std::conditional< BITS <= 8,  uint8_t,
      std::conditional< BITS <= 16, uint16_t,
      std::conditional< BITS <= 32, uint32_t, uint64_t > > >::type
         int_type;
};

int main()
{
   typename MyClass<8>::int_type a;
   std::cout << typeid(a).name() << std::endl;

   typename MyClass<16>::int_type b;
   std::cout << typeid(b).name() << std::endl;

   typename MyClass<32>::int_type c;
   std::cout << typeid(c).name() << std::endl;

   typename MyClass<60>::int_type d;
   std::cout << typeid(d).name() << std::endl;
}

输出,使用g ++ 5.4.0:

h
St11conditionalILb1EtS_ILb1EjmEE
St11conditionalILb0EtS_ILb1EjmEE
St11conditionalILb0EtS_ILb0EjmEE