Determining the type of index at compile time based on the maximum possible number

I am trying to create a type index_type_<N>

that will return an type

index based on N

, where N

is the maximum number that the indexes can go to.

So for example:

index_type_<32>::type index1; //uint8_t
index_type_<64000>::type index2;  //uint16_t
index_type_<18446744073709551>::type index3; //uint64_t

      

I have the following code that refuses to compile and I cannot determine the cause, despite googling the error messages, none of them apply to my situation.

    #include <iostream>

template<size_t N, typename T = void>
struct index_type_;

template<size_t N>
struct index_type_<N, typename std::enable_if<N <= 256, uint8_t>::value>
{
    typedef uint8_t type;
};
template<size_t N, typename T = void>
struct index_type_;

template<size_t N>
struct index_type_<N, typename std::enable_if<N <= 65536, uint16_t>::value>
{
    typedef uint16_t type;
};

template<size_t N>
struct index_type_<N, typename std::enable_if<N <= 4294967296, uint32_t>::value>
{
    typedef uint32_t type;
};

template<size_t N>
struct index_type_<N, typename std::enable_if<N <= 18446744073709551616ULL, uint64_t>::value>
{
    typedef uint64_t type;
};

int main()
{
    index_type_<32>::type index1;
    index_type_<232122>::type index2;
    index_type_<992532523>::type index3;
    index_type_<4213662352328854>::type index4;

    std::cout << "index1:" << sizeof(index1) << std::endl;
    std::cout << "index2:" << sizeof(index2) << std::endl;
    std::cout << "index3:" << sizeof(index3) << std::endl;
    std::cout << "index4:" << sizeof(index4) << std::endl;
}

      

Errors and sample code can be found here:

http://ideone.com/SJdKjr

Any help would be greatly appreciated, I feel like I'm missing something obvious.

+2


source to share


2 answers


All of your specializations are ambiguous. For example. which one is the best to choose?

template <std::size_t N>
struct Foo {
    // Specialization 1
};

template <std::size_t N>
struct Foo<N> {
    // Specialization 2
};

int main() {
    Foo<1> foo; // Error: partial specialization 'Foo<N>' does not
                //        specialize any template arguments.
}

      

Try something like this:



template <std::uintmax_t N>
struct index_type {
    using type = std::conditional_t<N <= 255, std::uint8_t,
                 std::conditional_t<N <= 63535, std::uint16_t,
                 std::conditional_t<N <= 4294967295, std::uint32_t,
                 std::conditional_t<N <= 18446744073709551615ULL, std::uint64_t,
                 std::uintmax_t>>>>;
};

template <std::uintmax_t N>
using index_type_t = typename index_type<N>::type;

      

Using:

index_type_t<64000> test; // unsigned int

      

+6


source


Using type list and recursive tests via numeric_limits

:

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

namespace detail
{
    template<class T>
    struct delay { using type = T; };

    template<class T, T t, class... IntTypes>
    struct select_int_type
    {
        static_assert(sizeof...(IntTypes) > 0,
                      "No integer type sufficiently big found.");
    };

    template<class T, T t, class Head, class... Tail>
    struct select_int_type<T, t, Head, Tail...>
    {
        using type = typename std::conditional<
              t <= std::numeric_limits<Head>::max()
            , delay<Head>
            , select_int_type<T, t, Tail...>
        >::type::type;
    };
}

template<std::uintmax_t N>
using select_uint_type =
    typename detail::select_int_type<decltype(N), N,
          std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t
        , std::uintmax_t
    >::type;

      

Usage example:

#include <iostream>

int main()
{
    select_uint_type<32> index1;
    select_uint_type<232122> index2;
    select_uint_type<992532523> index3;
    select_uint_type<4213662352328854> index4;

    std::cout << "index1:" << sizeof(index1) << std::endl;
    std::cout << "index2:" << sizeof(index2) << std::endl;
    std::cout << "index3:" << sizeof(index3) << std::endl;
    std::cout << "index4:" << sizeof(index4) << std::endl;
}

      



You can easily add signed types either through another alias template:

template<std::intmax_t N>
using select_int_type =
    typename detail::select_int_type<decltype(N), N,
          std::int8_t, std::int16_t, std::int32_t, std::int64_t
        , std::intmax_t
    >::type;

      

(I think make_signed

this is problematic here due to value based selection)

+3


source







All Articles