Hello everyone, I've only recently taken my first small steps into the world of metaprogramming, and now I've hit a snag. I'm trying to create a metafunction that returns the smallest unsigned integral type with at least the specified number of bits and, if no such type exists, reports an error. For example, ceil_uint<24> (named so for lack of a better name) returns the first member of the list consisting of unsigned char short unsigned int unsigned int long unsigned int whose number of bits is greater than or equal to 24. Now, ceil_uint<N> seems to work fine for 0 <= N <= 32, but with N outside this range, g++ (3.2) gives me a compilation error: [cej@kirk aux]$ g++ -I/usr/include/boost test.cpp -o test test.cpp: In function `int main()': test.cpp:48: conversion from `int' to non-scalar type `boost::mpl::void_' requested test.cpp:49: no match for `-- boost::mpl::void_&' operator test.cpp:50: no match for `boost::mpl::void_& == unsigned char' operator test.cpp:52: no match for `boost::mpl::void_& == short unsigned int' operator test.cpp:54: no match for `boost::mpl::void_& == unsigned int' operator I guess that a compilation error is desirable in these cases, but is there some MPL-blessed way to make the error message(s) more informative (i.e., tell the user that N is outside the valid range)? I'd greatly appreciate any and all suggestions for improving the metafunction. I'd also like to know the generally recommended way to separate the "invocation" of the metafunction from its definition. I intend to invoke the metafunction in a header file like this: namespace X { /* a definition of ceil_uint here would clutter the interface of class Y */ template<int N> class Y { /* ... */ typename ceil_uint<N>::type data; // invocation }; } Having the definition and the invocation in the same header file seems to clutter the interface of the class. /* test program */ #include "boost/mpl/vector.hpp" #include "boost/mpl/find_if.hpp" #include "boost/mpl/transform.hpp" #include "boost/mpl/multiplies.hpp" #include "boost/mpl/sizeof.hpp" #include "boost/mpl/greater_equal.hpp" #include "boost/mpl/int.hpp" #include "boost/mpl/at.hpp" #include "boost/mpl/distance.hpp" #include <limits> #include <iostream> namespace mpl = boost::mpl; using namespace mpl::placeholders; template<int N> struct ceil_uint { typedef mpl::vector< unsigned char, short unsigned int, unsigned int, long unsigned int
types;
typedef typename mpl::transform<
types,
mpl::multiplies<
mpl::sizeof_<_>,
mpl::int_
::type result;
typedef typename mpl::find_if< result, mpl::greater_equal< _1, mpl::int_<N> >
::type iter;
typedef typename mpl::at< types, typename mpl::distance< typename mpl::begin<result>::type, iter >::type
::type type; };
int main() { ceil_uint<24>::type i = 0; --i; if (i == std::numeric_limits<unsigned char>::max()) std::cout << "\"i\" is an unsigned char." << '\n'; else if (i == std::numeric_limits<short unsigned int>::max()) std::cout << "\"i\" is a short unsigned int." << '\n'; else if (i == std::numeric_limits<unsigned int>::max()) std::cout << "\"i\" is an unsigned int." << '\n'; else std::cout << "\"i\" is a long unsigned int." << '\n'; } TIA, Christian