C++ 根据模板整数参数选择整数类型

C++ 根据模板整数参数选择整数类型,c++,templates,C++,Templates,我想创建一个类模板,它接受一个无符号整数参数,并有一个成员u_uu,其类型是保存整数参数的最小无符号整数类型 因此: 对于A,u_u应为uint8_ut类型。A也一样。对于A,u_u应为uint16_uT等类型 如何实现这一点?您可以使用部分绑定模板的声明: template<uint8_t k> using A_uint8 = A<k, uint8_t>; template<uint8_t k> using A_uint16 = A<k, uint1

我想创建一个类模板,它接受一个无符号整数参数,并有一个成员u_uu,其类型是保存整数参数的最小无符号整数类型

因此:

对于A,u_u应为uint8_ut类型。A也一样。对于A,u_u应为uint16_uT等类型


如何实现这一点?

您可以使用部分绑定模板的声明:

template<uint8_t k>
using A_uint8 = A<k, uint8_t>;

template<uint8_t k>
using A_uint16 = A<k, uint16_t>;
然后:


这一元编程技巧实现了这一点:

template<unsigned int Y> struct typed
{
    typedef typename typed<(Y & (Y - 1)) == 0 ? Y / 2 : (Y & (Y - 1))>::type type;
};

template<> struct typed<0>
{
    typedef std::uint8_t type;
};

template<> struct typed<256>
{
    typedef std::uint16_t type;
};

template<> struct typed<65536>
{
    typedef std::uint32_t type;
};

/* ToDo - add more specialisations as necessary*/

template<unsigned k> class A
{
public:
    unsigned static const k_ = k; /*constexpr if your compiler supports it*/
    typename typed<k>::type u_;
};
用法正是问题所在

非专用模板版本采用以前的类型。类型化阻塞了静态递归。其他专业作为适当类型的锚定点

编译时可计算的Y&Y-1==0?Y/2:Y&Y-1通过删除Y的最右边的位来减少实例化的数量,直到达到2的幂,然后再除以2。确认@Jarod42。

使用C++11可以使用:


非常感谢。你们太棒了! 顺便说一下,我正在使用:

typedef typename std::conditional<k <= UINT8_MAX,
                        std::uint8_t,
                        typename std::conditional<k <= UINT16_MAX,
                        std::uint16_t,
                        typename std::conditional<k <= UINT32_MAX,
                        std::uint32_t,
                        std::uint64_t>::type>::type>::type TypeU;

std::pair<TypeU, std::shared_ptr<ProtoData>> min_;
std::pair<TypeU, std::shared_ptr<ProtoData>> max_;

如果我们想要的是:给定一个uint64_t模板参数,给出能够表示它的最小无符号类型,那么我们真正想要的只是编译时的一个简单迭代

namespace details {
    template <typename T>
    struct tag {
        using type = T;
    };

    // base case: just fail
    template <uint64_t V, typename... >
    struct min_unsigned_type;

    // recursive case: check using numeric_limits
    template <uint64_t V, typename T, typename... Ts>
    struct min_unsigned_type<V, T, Ts...>
    : std::conditional_t<(V <= std::numeric_limits<T>::max()),
                         tag<T>,
                         min_unsigned_type<V, Ts...>>
    { };
}
然后,只需一个别名即可将所有内容打包:

template <uint64_t V>
using min_unsigned_type = 
    typename details::min_unsigned_type<V, 
        uint8_t, uint16_t, uint32_t, uint64_t>::type;
这样做的另一个好处是,可以轻松指定要执行的操作,甚至可以在必要时添加更大的无符号类型

最后,你们班:

template <uint64_t V>
struct A {
    static constexpr uint64_t k_ = V;
    min_unsigned_type<V> u_;
};

如果k是一个单位,那么这意味着什么?:…=A.256超出了uint8的承受能力,所以这对我来说没有意义谁投票支持了这个问题??它毫无意义,直到我花了一段时间从答案中推断出问题的真正目的。当k的类型为uint8\t时,256怎么可能是参数?允许的最大k是255k,正如@AaronMcDaid指出的问题一样,这并不能解决自动选择类型的原始问题,而不是由调用API的代码手动完成。我在自动选择中看到的主要优点是宏和常量可以用于k,并且类型将使用宏或常量自动更新。
typedef typename std::conditional<k <= UINT8_MAX,
                        std::uint8_t,
                        typename std::conditional<k <= UINT16_MAX,
                        std::uint16_t,
                        typename std::conditional<k <= UINT32_MAX,
                        std::uint32_t,
                        std::uint64_t>::type>::type>::type TypeU;

std::pair<TypeU, std::shared_ptr<ProtoData>> min_;
std::pair<TypeU, std::shared_ptr<ProtoData>> max_;
template<uintmax_t Id>
struct A;

template<>
struct A<0>{
    enum {id = 0};
    using type = uint8_t;
};

template<>
struct A<255>{
    enum {id = 255};
    using type = uint8_t;
};

template<>
struct A<256>{
    enum {id = 256};
    using type = uint16_t;
};

int main(){
    typename A<255>::type a0 = 255; // uint8_t
    typename A<256>::type a1 = 256; // uint16_t
}
template<uintmax_t Value>
struct A{
    enum {value = Value};
    using type = std::conditional_t<
        (Value <= std::numeric_limits<uint8_t>::max()), uint8_t,
            std::conditional_t<
                (Value <= std::numeric_limits<uint16_t>::max()), uint16_t,
                    std::conditional_t<
                        (Value <= std::numeric_limits<uint32_t>::max()), uint32_t
                            std::conditional_t<
                                (Value <= std::numeric_limits<uint64_t>::max()), uint64_t, uintmax_t
                            >
                    >
            >
    >;
};
namespace details {
    template <typename T>
    struct tag {
        using type = T;
    };

    // base case: just fail
    template <uint64_t V, typename... >
    struct min_unsigned_type;

    // recursive case: check using numeric_limits
    template <uint64_t V, typename T, typename... Ts>
    struct min_unsigned_type<V, T, Ts...>
    : std::conditional_t<(V <= std::numeric_limits<T>::max()),
                         tag<T>,
                         min_unsigned_type<V, Ts...>>
    { };
}
template <uint64_t V>
using min_unsigned_type = 
    typename details::min_unsigned_type<V, 
        uint8_t, uint16_t, uint32_t, uint64_t>::type;
template <uint64_t V>
struct A {
    static constexpr uint64_t k_ = V;
    min_unsigned_type<V> u_;
};