Boost logo

Boost :

From: Alexander Nasonov (alnsn_at_[hidden])
Date: 2002-10-23 03:30:31


Douglas Paul Gregor wrote:
>
> template<typename Derived>
> struct mixin {
> Derived operator*() const
> {
> return boost::call(dereference(),
> static_cast<const Derived&>(*this));
> }
> };
> };
>
> The mixin will be inherited by dynamic_any<Sequence> as
> mixin<dynamic_any<Sequence> >. That sticks the dereference operator
> directly in dynamic_any, so that member functions, operators, etc. can be
> applied directly to dynamic_any objects that have them mixed-in.

Good idea.

There are many problems with operators. Here are some of them:

1. unary -. What about promotions (5.3.1/7)?

struct negate : dynamic_any_function_v<dynamic_return>
{
  template<typename T>
  typename promote<T>::type // or T?
  operator()(const T & value)
  {
    return -value;
  }
};

If negate returns promoted type then this code is legal:

  dynamic_any<mpl::list<negate> > a('z');
  assert(a.type() == typeid(char));
  a = -a;
  assert(a.type() == typeid(int));

and unary + can have some usage:

  a = +a; // can be promoted

2. Dereference of smart pointers. May be add some policy to dereference
function (see example5.cpp below)?
3. General problem with binary functions. Currently, binary functions can be
called only when both arguments have the same type. I did so to protect
from argument slicing. Now I think that it's better to remove this
restriction. After all, user can easily protect himself! For example, if X
and Y are classes and x and y are defined as:

typedef dynamic_any<mpl::list<foo> > any;
any x = X();
any y = Y();

then implementation of call(foo(), x, y) can look like this:

// pseudocode
result call(function func, any x, any y)
{
  bool all_extracted = false;
  try
  {
    X & arg1 = extract<X &>(x);
    X & arg2 = extract<X &>(y);
    all_extracted = true;
    return func(arg1, arg2);
  }
  catch(const bad_dynamic_any_cast &)
  {
    if(all_extracted)
      throw;
    Y & arg1 = extract<Y &>(x);
    Y & arg2 = extract<Y &>(y);
    return func(arg1, arg2);
  }
}

4. Comparing values of different type.

For example:

struct less : dynamic_any_function_vv<dynmaic_return>
{
  template<typename T>
  T operator()(const T & v1, const T & v2)
  {
    using std::less;
    return less(v1, v2);
  }
};

This call should throw:

dynamic_any<mpl::list<less> > a(0), b(1U);
bool cmp = call(less(), a, b); // throw

Should operator< also throw? Or may be this is a better way:

template<class Sequence1, class Sequence2>
bool operator<(
  const dynamic_any<Sequence1> & v1,
  const dynamic_any<Sequence2> & v2)
{
  if(v1.type() != v2.type())
    return v1.type().before(v2.type());
  if(v1.empty())
    return false;
  return call(less(), v1, v2);
}

Best regards,
Alexander Nasonov
mailbox: alnsn
server: mail.ru

// example5.cpp:

#include "dynamic_any.hpp"
#include <boost/type_traits.hpp>
#include <boost/mpl/list.hpp>
#include <iostream>
#include <exception>
#include <stdexcept>

using namespace boost;

struct dereference : dynamic_any_function_v<dynamic_return>
{
  // TODO: support for shared_ptr
  template<typename T>
  const typename remove_pointer<T>::type & operator()(const T & ref)
  {
    return do_dereference<typename remove_pointer<T>::type>(ref);
  }

private:

  template<typename T>
  static const T & do_dereference(const T * ptr)
  {
    if(ptr == 0)
      throw std::runtime_error("dereference of a null pointer");
    return *ptr;
  }

  template<typename T>
  static const T & do_dereference(const T &)
  {
    throw std::runtime_error("not a pointer");
  }
};

template<class OperationList>
dynamic_any<OperationList> operator*(
  const dynamic_any<OperationList> & value)
{
  return call(dereference(), value);
}

struct increment : dynamic_any_function_r<void>
{
  template<typename T>
  void operator()(T & ref)
  {
    ++ref;
  }
};

template<class OperationList>
dynamic_any<OperationList> & operator++(
  dynamic_any<OperationList> & ref)
{
  call(increment(), ref);
  return ref;
}

typedef dynamic_any<mpl::list<dereference, increment> > any;

int main()
{
  using namespace std;

  int two_integers[2] = { 1, 2 };
  int * p = &two_integers[0];

  any a(p);
  cout << extract<int *>(a) << endl;
  cout << *extract<int *>(a) << endl;

  ++a;
  cout << extract<int *>(a) << endl;
  cout << *extract<int *>(a) << endl;

  a = *a;
  cout << extract<int>(a) << endl;

  ++a;
  cout << extract<int>(a) << endl;

  p = 0;
  any b(p);

  try
  {
    // You can comment next line
    a = *a; // not a pointer
    b = *b; // dereference of a null pointer
  }
  catch(std::exception & ex)
  {
    cout << ex.what() << endl;
  }
}


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