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:
Any help would be greatly appreciated, I feel like I'm missing something obvious.
source to share
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
source to share
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)
source to share