自动选择足够大的变量类型以保存指定的数字

jco*_*der 54 c++ templates template-meta-programming

在C++中是否有任何方法可以定义一个足以容纳最多特定数字的类型,大概是使用一些聪明的模板代码.例如,我希望能够写: -

Integer<10000>::type dataItem;
Run Code Online (Sandbox Code Playgroud)

并将该类型解析为足以保持指定值的最小类型?

背景:我需要使用外部数据文件中的脚本生成一些变量定义.我想我可以使脚本看看值,然后使用uint8_t,uint16_t,uint32_t等,这取决于价值,但它似乎更优雅建设规模到生成的C++代码.

我看不出任何方法可以制作一个可以做到这一点的模板,但是知道C++模板,我确信有办法.有任何想法吗?

Geo*_*che 57

Boost.Integer已经具有整数类型选择功能:

boost::int_max_value_t<V>::least
Run Code Online (Sandbox Code Playgroud)

最小的内置有符号整数类型,可以包含0 - V范围内的所有值.参数应为正数.

boost::uint_value_t<V>::least
Run Code Online (Sandbox Code Playgroud)

最小的内置无符号整数类型,可以保存所有正值,包括V.参数应为正数.


fre*_*low 41

当然,这是可能的.这是成分.让我们从我最喜欢的两个元函数开始:

template<uint64_t N>
struct constant
{
    enum { value = N };
};

template<typename T>
struct return_
{
    typedef T type;
};
Run Code Online (Sandbox Code Playgroud)

然后,一个元函数计算存储数字所需的位数:

template<uint64_t N>
struct bitcount : constant<1 + bitcount<(N>>1)>::value> {};

template<>
struct bitcount<0> : constant<1> {};

template<>
struct bitcount<1> : constant<1> {};
Run Code Online (Sandbox Code Playgroud)

然后,一个计算字节数的元函数:

template<uint64_t N>
struct bytecount : constant<((bitcount<N>::value + 7) >> 3)> {};
Run Code Online (Sandbox Code Playgroud)

然后,返回给定字节数的最小类型的元函数:

template<uint64_t N>
struct bytetype : return_<uint64_t> {};

template<>
struct bytetype<4> : return_<uint32_t> {};

template<>
struct bytetype<3> : return_<uint32_t> {};

template<>
struct bytetype<2> : return_<uint16_t> {};

template<>
struct bytetype<1> : return_<uint8_t> {};
Run Code Online (Sandbox Code Playgroud)

最后,你要求的元功能:

template<uint64_t N>
struct Integer : bytetype<bytecount<N>::value> {};
Run Code Online (Sandbox Code Playgroud)

  • 这是我见过的模板元编程的最新和_best解释的例子之一:) (2认同)
  • 这不是神奇地假设`CHAR_BIT == 8`吗?:-) (2认同)
  • 呵呵......无论如何,我真正的"道德问题"有很多答案,就是使用像`uint16_t`这样的固定宽度类型不需要任何形式的TMP:如果数据类型的大小已经从标准,独立于平台,然后我们真的不需要C++解决方案 - OP的预处理器可以立即做出正确的决定,结果在所有平台上都是相同的.如果你想找到与它们的大小和CHAR_BIT无关的拟合*原型*类型,我认为这会更有趣......但我并不认为那会有用:-) (2认同)

Max*_*kin 25

#include <stdint.h>

template<unsigned long long Max>
struct RequiredBits
{
    enum { value =
        Max <= 0xff       ?  8 :
        Max <= 0xffff     ? 16 :
        Max <= 0xffffffff ? 32 :
                            64
    };
};

template<int bits> struct SelectInteger_;
template<> struct SelectInteger_ <8> { typedef uint8_t type; };
template<> struct SelectInteger_<16> { typedef uint16_t type; };
template<> struct SelectInteger_<32> { typedef uint32_t type; };
template<> struct SelectInteger_<64> { typedef uint64_t type; };

template<unsigned long long Max>
struct SelectInteger : SelectInteger_<RequiredBits<Max>::value> {};

int main()
{
    SelectInteger<12345>::type x = 12345;
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,`256ull*256*256*256*256*256*256*256`为零. (5认同)
  • 就个人而言,我认为这是解决问题的最佳方案. (2认同)

Jac*_* V. 7

你是否一定想要最小的,而不是使用int小于int的类型?

如果没有,并且你的编译器支持它,你能做到:

int main()
{
    typeof('A') i_65 = 0; // declare variable 'i_65' of type 'char'
    typeof(10) i_10 = 0; // int
    typeof(10000) i_10000 = 0; // int
    typeof(1000000000000LL) i_1000000000000 = 0; // int 64
}
Run Code Online (Sandbox Code Playgroud)


Ker*_* SB 6

有条件的怎么样:

#include <type_traits>
#include <limits>

template <unsigned long int N>
struct MinInt
{
  typedef typename std::conditional< N < std::numeric_limits<unsigned char>::max(),
       unsigned char, std::conditional< N < std::numeric_limits<unsigned short int>::max(),
         unsigned short int>::type,
         void*>::type>::type
    type;
};
Run Code Online (Sandbox Code Playgroud)

这必须扩展到按顺序包含所有所需类型; 在最后阶段,如果值太大,你可以使用enable_if而不是conditional在那里有一个实例化错误.


lin*_*ina 5

使用 C++11 轻松实现:

#include <cstdint>
#include <limits>
#include <type_traits>


template <class T, class U =
    typename std::conditional<std::is_signed<T>::value,
      std::intmax_t,
      std::uintmax_t
    >::type>
constexpr bool is_in_range (U x) {
  return (x >= std::numeric_limits<T>::min())
      && (x <= std::numeric_limits<T>::max());
}

template <std::intmax_t x>
using int_fit_type =
    typename std::conditional<is_in_range<std::int8_t>(x),
      std::int8_t,
      typename std::conditional<is_in_range<std::int16_t>(x),
        std::int16_t,
        typename std::conditional<is_in_range<std::int32_t>(x),
          std::int32_t,
          typename std::enable_if<is_in_range<std::int64_t>(x), std::int64_t>::type
        >::type
      >::type
    >::type;

template <std::uintmax_t x>
using uint_fit_type =
    typename std::conditional<is_in_range<std::uint8_t>(x),
      std::uint8_t,
      typename std::conditional<is_in_range<std::uint16_t>(x),
        std::uint16_t,
        typename std::conditional<is_in_range<std::uint32_t>(x),
          std::uint32_t,
          typename std::enable_if<is_in_range<std::uint64_t>(x), std::uint64_t>::type
        >::type
      >::type
    >::type;
Run Code Online (Sandbox Code Playgroud)