如何获得宽度为 maximum/minimum 的整数?

How do I get an int with a maximum/minimum width?

我想要一个 int 具有特定宽度的向量化目的。

类似 int_atleast< 3 /*bytes*/ > 的东西应该给出 int32_t,而 int_atmost< 5 > 应该给出相同的 int32_t

我试图通过模板特化来实现它,但碰壁了,因为我需要特化每个可能的参数。我想到了递归,但它似乎是对标准中可能已经存在的东西的过于复杂的解决方案。我该怎么办?

我会使用 TypeList<Args...> 之类的方法,然后根据您的过滤器删除选项。我相信这完全按照需要实现了您的类型特征。

例如:

#include <type_traits>
#include <cstddef>

template <typename ... Args>
struct TypeList{};

template <typename List>
struct FrontImpl;
template <typename Front, typename ... Args>
struct FrontImpl<TypeList<Front, Args...>>
{
    using type = Front;
};
template <typename List>
using Front = typename FrontImpl<List>::type;

template <typename T>
struct Id{ using type = T; };

template <typename List>
struct BackImpl;
template <typename ... Args>
struct BackImpl<TypeList<Args...>>
{
    using type = typename decltype((Id<Args>{}, ...))::type;
};
template <typename T>
using Back = typename BackImpl<T>::type;

template <typename F, typename List, typename Result = TypeList<>>
struct FilterImpl;

template <typename F, typename ... Done>
struct FilterImpl<F, TypeList<>, TypeList<Done...>>
{
    using type = TypeList<Done...>;
};

template <typename F, typename Front, typename ... Rest, typename ... Done>
struct FilterImpl<F, TypeList<Front, Rest...>, TypeList<Done...>>
{
    using type = std::conditional_t
    <
        F::template Test<Front>,
        typename FilterImpl<F, TypeList<Rest...>, TypeList<Done..., Front>>::type,
        typename FilterImpl<F, TypeList<Rest...>, TypeList<Done...>>::type
    >;
};

template <typename F, typename List>
using Filter = typename FilterImpl<F, List>::type;

template <typename F, typename List>
using FirstFiltered = Front<Filter<F, List>>;

template <typename F, typename List>
using LastFiltered = Back<Filter<F, List>>;

template <size_t N>
struct SizeAtLeast
{
    template <typename T>
    static constexpr bool Test = sizeof(T) >= N;
};

template <size_t N>
struct SizeAtMost
{
    template <typename T>
    static constexpr bool Test = sizeof(T) <= N;
};

template <size_t N>
struct SizeBetween
{
    template <typename T>
    static constexpr bool Test = N <= sizeof(T) and sizeof(T) <= N;
};

然后使用这个定义你需要的别名:

#include <cstdint>

// As per interface requirement
template <size_t N>
using int_atmost = LastFiltered<SizeAtMost<N>, TypeList<int8_t, int16_t, int32_t, int64_t>>;

template <size_t N>
using int_atleast = FirstFiltered<SizeAtLeast<3>, TypeList<int8_t, int16_t, int32_t, int64_t>>;

https://godbolt.org/z/Wh31Pvcjh

C++17 解决方案非常简单。 if constexpr 允许我们根据常量表达式更改函数的 return 类型。这允许人们相当简洁地编写算法

namespace detail {
    template<unsigned W>
    auto compute_atleast_integer() {
        if constexpr (W <= 1)
            return uint8_t{};
        else if constexpr (W <= 2)
            return uint16_t{};
        else if constexpr (W <= 4)
            return uint32_t{};
        else if constexpr (W <= 8)
            return uint64_t{};
    }
}

template<unsigned W>
using int_atleast = decltype(detail::compute_atleast_integer<W>());

当没有这样的整数可用时,这也有给出 void 的新兴 属性。这是一个更软的错误,可以在 SFINAE 上下文中用来做一些智能的事情。

I tried to implement this with template specialization, but hit a wall because I'd need to specialize every possible argument.

编写类型特征不需要大量样板代码,恕我直言,但您的里程数可能会有所不同。

#include <cstdint>
#include <type_traits>

template< unsigned Bits >
    requires (Bits <= 64) // C++20, remove this line if you need C++17
using int_atleast_t
    = std::conditional_t< Bits <= 8, std::int8_t
    , std::conditional_t< Bits <= 16, std::int16_t
    , std::conditional_t< Bits <= 32, std::int32_t, std::int64_t >>>;

constexpr unsigned operator"" _bits (unsigned long long bits) {
    return bits;
}

constexpr unsigned operator"" _bytes (unsigned long long bytes) {
    return bytes * 8;
}

int main()
{
    static_assert(std::is_same_v<int32_t, int_atleast_t< 30_bits >>);
    static_assert(std::is_same_v<int8_t, int_atleast_t< 8_bits >>);
    static_assert(not std::is_same_v<int16_t, int_atleast_t< 3_bytes >>);
}