Boost logo

Boost :

From: Maurizio Vitale (mav_at_[hidden])
Date: 2007-04-13 08:11:49


This is a short example that I put together to show how to use boost::proto for
modifying the semantics of C++ builtin datatypes.

In particolar we define unsigned integers for which we can define a width
(less than sizof(unsigned int)*8). Values are masked and bits outside the
declared width are discarded. We also redefine the shift operator so that
both positive and negative shift counts are supported.

The code compiles fine with GCC 4.1.2.

It fails miserably under the Intel C++ compiler 9.1.046, which is really really
unhappy about the context being a template class. I haven't investigated further,
but given the fact that the Intel compiler is EDG based I suspect there's something
wrong either in my code or in boost::proto.

I hope Eric can find the time to review it and maybe add it to the boost::proto
examples. I would certainly have benefited from something like this being available.
On the other hand, I've learned more by doing it. Thanks to Eric for
having helped me and for making boost::proto available.

I'm sure I'll have more questions as I proceed in proto-izing my numeric library.
Regards,

        Maurizio

#include <iostream>
#include <boost/xpressive/proto/proto.hpp>
#include <boost/xpressive/proto/context.hpp>
#include <boost/xpressive/proto/extends.hpp>
#include <boost/xpressive/proto/debug.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/typeof/std/ostream.hpp>

#include <boost/mpl/integral_c.hpp>

namespace proto=boost::proto;
namespace mpl=boost::mpl;

struct my_domain : proto::domain<> {};

template<typename> struct my_context;

template <typename Expr>
struct my_expr : proto::extends<Expr, my_expr<Expr>, my_domain> {
  typedef proto::extends<Expr, my_expr<Expr>, my_domain> base_type;

  my_expr (Expr const& expr = Expr()) : base_type (expr) {};

  using base_type::operator =;

  typedef unsigned int result_type;

  operator result_type () const {
    return proto::eval(*this, my_context<Expr> ());
  }
};

namespace boost { namespace proto {
  template<typename Expr>
  struct generate<my_domain, Expr> {
    typedef my_expr<Expr> type;
      
    static type make (Expr const& expr) {
      return type (expr);
    }
  };
} } // end namespace boost::proto

template<typename T> struct number;

template<typename T>
std::ostream& operator << (std::ostream& os, const number<T> o);

template<typename T>
struct number {
  friend std::ostream& operator << <> (std::ostream& os, const number<T> o);
  unsigned int m_data;
};

template<typename T>
std::ostream& operator << (std::ostream& os, const number<T> n) { os << "~" << n.m_data << "~"; return os; }

template<typename Expr>
struct my_context : proto::callable_context<const my_context<Expr> > {
  typedef int result_type; // later we'll compute this from Expr

  template<typename T>
  int operator () (proto::tag::terminal, number<T> n) const { return n.m_data; }

  template<typename Left, typename Right>
  int operator () (proto::tag::left_shift, const Left& left, const Right& right) const {
    int shift = proto::eval (right, *this);
    if (shift >= 0)
      return proto::eval (left, *this) << shift;
    else
      return proto::eval (left, *this) >> -shift;
  }

  template<typename Left, typename Right>
  int operator () (proto::tag::right_shift, const Left& left, const Right& right) const {
    int shift = proto::eval (right, *this);
    if (shift >= 0)
      return proto::eval (left, *this) >> shift;
    else
      return proto::eval (left, *this) << -shift;
  }
};

template<int N>
struct my_int : my_expr<typename proto::terminal<number<mpl::int_<N> > >::type>
{
  typedef my_expr<typename proto::terminal<number<mpl::int_<N> > >::type> expr_type;

  my_int () {}
  my_int (int i) : expr_type (expr_type::type::make (mask (i))) {}

  template<typename Expr>
  my_int& operator = (const Expr& e) {
    proto::arg (*this).m_data = mask (proto::eval(e, my_context<Expr> ()));
    return *this;
  }

  unsigned int mask (unsigned int value) {
    return value & ((1U << N) - 1);
  }
};

int main (int, char**) {
  my_int<4> b(18);
  my_int<2> c;
  int i;

  c=b*b+1; // c = 1

  i = c << -1; // i = 0
  std::cout << "i=" << i << "\n";

  i = b << -1; // i = 1
  std::cout << "i=" << i << "\n";

  i = b << 5; // i = 64
  std::cout << "i=" << i << "\n";
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk