|
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