Boost logo

Boost :

Subject: Re: [boost] (Boost.)Overload vs Boost.Functional/OverloadedFunction (was Re: Status of proposed boost.overload?)
From: Marco Cecchetti (mrcekets_at_[hidden])
Date: 2012-03-26 05:20:12


On Sun, 25 Mar 2012 00:15:38 +0100, lcaminiti <lorcaminiti_at_[hidden]>
wrote:

> How's this different from:
> http://svn.boost.org/svn/boost/trunk/libs/functional/overloaded_function/doc/html/index.html
>

Hi Lorenzo,
(Boost.)Overload is a dynamic wrapper of multiple callable objects.
All started from a Joel de Guzman's post where he showed a proof
of concept of a thin-wrapper of several Boost.Functions.
See: http://lists.boost.org/Archives/boost/2007/09/127906.php
On that code base, I designed (Boost.)Overload that provides an
interface similar to Boost.Function.

A first difference is that with (Boost.)Overload is possible
to create an empty boost::overload object, and then set up
callable targets at a later time, obviously the library provides
methods for checking if a given callable target is empty.
That matches exactly what Boost.Function does.
Here's a basic example extracted from the tutorial:

/////////////////////////////////////////////////////////////////
#include <boost/detail/lightweight_test.hpp>
#include <boost/overload.hpp>

int int_sum(int x, int y)
{
             return x + y;
}

float float_inc(float x )
{
             return x + 1.0f;
}

int main()
{
             boost::overload<int (int, int ), float (float )> f;

             f.set(&int_sum); // here automatic call signature
             f.set(&float_inc); // deduction occurs

             int r1 = f(1, 2); // invokes int_sum
             float r2 = f(3.0f); // invokes float_inc

             BOOST_ASSERT( r1 == 3 );
             BOOST_ASSERT( r2 == 4.0f );

             return boost::report_errors();
}
/////////////////////////////////////////////////////////////////

One can set all callable targets at once: f.set(&float_inc, &int_sum).
Order does not matter, the callable entity is assigned
automatically to the embedded boost::function with a matching call
signature. However that works for monomorphic callable objects only.

For polymorphic one it is needed to utilize the set method based
on the call signature syntax:

/////////////////////////////////////////////////////////////////
#include <boost/detail/lightweight_test.hpp>
#include <boost/overload.hpp>

/* polymorphic function object */
struct bar
{
             int operator()(int ) { return 1; }

             template<typename T>
             int operator()(T ) { return ( 2 + sizeof(T) ); }
};

int main()
{
             boost::overload<int (int ), int (char ), int (double )> f;

             // function object
             bar foo;

             // we use the call signature syntax for setting a copy of
             // foo as object target for the call signature int (char )
             // only
             f.set<int (char )>(foo);
             // invokes int foo(char ) template instantiation
             BOOST_ASSERT( f('x') == foo('x') );
             // through the empty<Signature>() method we check
             // that no other object target has been set up
             BOOST_ASSERT( f.empty<int(int )>() );
             BOOST_ASSERT( f.empty<int(double )>() );

             // now we set a copy of foo as object target tied to
             // the call signature int( int )
             f.set<int (int )>(foo);
             BOOST_ASSERT( f('x') == foo('x') );
             BOOST_ASSERT( f(1) == foo(1) );
             BOOST_ASSERT( f.empty<int(double )>() );

             // and finally we set up also the object target
             // for the int(double ) call signature
             f.set<int (double )>(foo);
             BOOST_ASSERT( f('x') == foo('x') );
             BOOST_ASSERT( f(1) == foo(1) );
             BOOST_ASSERT( f(1.0) == foo(1.0) );

             return boost::report_errors();
}
/////////////////////////////////////////////////////////////////

In case we are dealing with a statefull function object copying
it several times is both expensive and probably also semantically
incorrect. The solution is to wrap the function object with
boost::ref.

The call signature based syntax can be used with overloaded free
and member functions, too.

Another point where the two libraries differ is that
a boost::overload object that supports a given call signature S
can be passed everywhere an object of type boost::function<S> is
expected.

Lately I implemented also support for boost::result_of.
So it is possible to utilize (Boost.)Overload with Boost.Fusion
algorithms such as boost::fusion::for_each.

A natural use case is to utilize (Boost.)Overload for generating
a Boost.Variant visitor:

/////////////////////////////////////////////////////////////////
#include <boost/variant.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <boost/overload.hpp>

template<
     typename Overload,
     typename R = ::boost::detail::static_visitor_default_return
>
struct overloaded_visitor : public Overload
{
             typedef R result_type;
};

int apply_to_int(int )
{
             return 1;
}

int apply_to_string(const std::string & )
{
             return 2;
}

typedef boost::overload<int (int ), int(const std::string & )>
         overload_type;

typedef overloaded_visitor<overload_type, int> visitor_type;

int main()
{

             boost::variant< int, std::string > u("hello world");

             visitor_type my_visitor;
             my_visitor.set( &apply_to_int, &apply_to_string );

             int result = boost::apply_visitor( my_visitor, u );
             BOOST_ASSERT( result == 2 );

             return boost::report_errors();
}
/////////////////////////////////////////////////////////////////

You can find more details on the documentation page:
http://svn.boost.org/svn/boost/sandbox/overload/trunk/libs/overload/docs/html/index.html

Kind Regards,
-- Marco

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

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