How to write "meta, if more, if .." in C ++?

I am just learning the basics of metaprogramming in C ++, and I thought it would be nice to see how others can solve the following question. Also, it would be really nice to see a solution using Boost metaprogramming libraries because I find them a dark corner for me. So the question is, can this be rewritten more elegantly?

Suppose we have the following structure:

template <std::size_t size> struct type_factory { typedef typename type_factory_impl<size>::type type; }; 

This structure should typedef type , depending on the value of size . type_factory_impl is an implementation of type_factory . The algorithm used to determine type :

 if(size % bits<unsigned long long>::value == 0) typedef unsigned long long type; else if(size % bits<unsigned long>::value == 0) typedef unsigned long type; else if(size % bits<unsigned int>::value == 0) typedef unsigned int type; else if(size % bits<unsigned short int>::value == 0) typedef unsigned short int type; else if(size % bits<unsigned char>::value == 0) typedef unsigned char type; else static_assert(false, "The type should be multiple of 'unsigned char' size"); 

I solved this metaprogram in two ways. The first uses direct pattern matching, and the second uses meta if-else . As a common code between both solutions, consider the following:

 #include <cstddef> #include <climits> typedef unsigned char uchar; typedef unsigned short int usint; typedef unsigned int uint; typedef unsigned long ulong; typedef unsigned long long ulonglong; // Returns how many bits in Unsigned_Type template <typename Unsigned_Type> struct bits { enum { value = sizeof(Unsigned_Type)*CHAR_BIT }; }; // struct type_factory_impl ... template <std::size_t size> struct type_factory { typedef typename type_factory_impl<size>::type type; }; int main() { auto a = type_factory<8>::type(0); // unsigned char auto b = type_factory<16>::type(0); // unsigned short int auto c = type_factory<24>::type(0); // unsigned char auto d = type_factory<32>::type(0); // unsigned long auto e = type_factory<40>::type(0); // unsigned char auto f = type_factory<48>::type(0); // unsigned short int auto g = type_factory<56>::type(0); // unsigned char auto h = type_factory<64>::type(0); // unsigned long long } 

First decision:

 template <bool is_uchar> struct unsigned_char { typedef unsigned char type; static_assert(is_uchar, "error: size must be multiple of 'unsigned char' size"); }; template <> struct unsigned_char <true> { typedef uchar type; }; template <bool is_usint, std::size_t size> struct unsigned_short_int { typedef typename unsigned_char<size % bits<uchar>::value == 0>::type type; }; template <std::size_t size> struct unsigned_short_int <true, size> { typedef usint type; }; template <bool is_uint, std::size_t size> struct unsigned_int { typedef typename unsigned_short_int<size % bits<usint>::value == 0, size>::type type; }; template <std::size_t size> struct unsigned_int <true, size> { typedef uint type; }; template <bool is_ulong, std::size_t size> struct unsigned_long { typedef typename unsigned_int<size % bits<uint>::value == 0, size>::type type; }; template <std::size_t size> struct unsigned_long <true, size> { typedef ulong type; }; template <bool is_ulonglong, std::size_t size> struct unsigned_long_long { typedef typename unsigned_long<size % bits<ulong>::value == 0, size>::type type; }; template <std::size_t size> struct unsigned_long_long <true, size> { typedef ulonglong type; }; template <std::size_t size> struct type_factory_impl { typedef typename unsigned_long_long<size % bits<ulonglong>::value == 0, size>::type type; }; 

The second solution:

 template <bool condition, typename Then, typename Else> struct IF { typedef Else type; }; template <typename Then, typename Else> struct IF <true, Then, Else> { typedef Then type; }; template <std::size_t size> struct type_factory_impl { typedef typename IF<size % bits<ulonglong>::value == 0, ulonglong, typename IF<size % bits<ulong>::value == 0, ulong, typename IF<size % bits<uint>::value == 0, uint, typename IF<size % bits<usint>::value == 0, usint, typename IF<size % bits<uchar>::value == 0, uchar, uchar>::type >::type >::type >::type >::type type; }; 
+6
source share
2 answers

Like you, I consider Boost.MPL a black magic, so I thought it might be a reason to try and use it to answer your question. Please keep in mind that this is my first attempt with this library, and that some gurus there are likely to provide a better solution.

The idea is to find boost :: mpl :: find_if to find the first matching element in the type sequence.

 typedef boost::mpl::vector < unsigned long long, unsigned long, unsigned int, unsigned short, unsigned char > type_sequence; template<std::size_t size> struct predicate { template<class T> struct apply { static const bool value = (size % bits<T>::value == 0); }; }; template<std::size_t size> struct type_factory_impl { typedef typename boost::mpl::find_if < type_sequence, typename predicate<size>::apply<boost::mpl::_1> >::type iterator_type; typedef typename boost::mpl::deref<iterator_type>::type type; }; 

I think a good result:

alt text

I do not handle the "default" case, but my brain just started to bleed through my nose, I will try to finish my answer later and hope this helps.

+4
source

Is there something wrong with the specialization?

 template<size_t N> struct lowest_bit { enum { lowest_bit_removed = N & (N-1), value = N ^ lowest_bit_removed }; }; template<size_t size> struct type_factory_impl { typedef uchar type; }; template<> struct type_factory_impl<sizeof(ushort) *CHAR_BIT> { typedef ushort type; }; template<> struct type_factory_impl<sizeof(uint) *CHAR_BIT> { typedef uint type; }; template<> struct type_factory_impl<sizeof(ulong) *CHAR_BIT> { typedef ulong type; }; template<> struct type_factory_impl<sizeof(ulonglong)*CHAR_BIT> { typedef ulonglong type; }; template<size_t size> struct type_factory { typedef typename type_factory_impl<lowest_bit<size>::value>::type type; }; 
+4
source

All Articles