Boost logo

Boost Users :

From: cj2048 (cj2048_at_[hidden])
Date: 2003-03-22 17:15:11


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_at_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_<std::numeric_limits<unsigned char>::digits>
>
>::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


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net