|
Boost : |
From: Marco Costalba (mcostalba_at_[hidden])
Date: 2007-10-01 11:20:08
On 10/1/07, Joel de Guzman <joel_at_[hidden]> wrote:
> Marco Costalba wrote:
> > On 10/1/07, Marco Costalba <mcostalba_at_[hidden]> wrote:
> >> On 10/1/07, Joel de Guzman <joel_at_[hidden]> wrote:
> >>> Joel de Guzman wrote:
> >>>
> >>> Hence, I'd like to propose an extension (or a separate library)
> >>> for allowing overloads for boost.function. The example above can
> >>> be declared as:
>
> [snip]
> >
> > A little bit more complex but works for any number of arguments (sigantures).
>
> Smart, Marco! You know fusion well :-)
>
Well, not so well, it doesn't compile...but I've looked also at tuples
in the meantime and this one actually works:
Sorry to post the file but I have no access to my host:
/*=============================================================================
Copyright (c) 2006 Joel de Guzman
Use, modification and distribution is subject to the Boost Software
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
==============================================================================*/
#if !defined(BOOST_OVERLOAD_06162006_2345)
#define BOOST_OVERLOAD_06162006_2345
#include <boost/function.hpp>
#include <boost/tuple/tuple.hpp>
namespace boost
{
template <int size>
struct final_overload_function
{
struct final;
static int const index = size;
void operator()(final*) const {}
};
template <typename Base, typename Derived, typename Sig>
struct overload_function;
template <typename Base, typename Derived, typename R>
struct overload_function<Base, Derived, R()> : Base
{
using Base::operator();
static int const index = Base::index - 1;
R operator()() const
{
return get<index>(static_cast<Derived const*>(this)->functions)();
}
};
template <typename Base, typename Derived, typename R, typename A0>
struct overload_function<Base, Derived, R(A0)> : Base
{
using Base::operator();
static int const index = Base::index - 1;
R operator()(A0 a0) const
{
return get<index>(static_cast<Derived const*>(this)->functions)(a0);
}
};
template <typename Base, typename Derived, typename R, typename
A0, typename A1>
struct overload_function<Base, Derived, R(A0, A1)> : Base
{
using Base::operator();
static int const index = Base::index - 1;
R operator()(A0 a0, A1 a1) const
{
return get<index>(static_cast<Derived
const*>(this)->functions)(a0, a1);
}
};
template <typename Base, typename Derived, typename R, typename
A0, typename A1, typename A2>
struct overload_function<Base, Derived, R(A0, A1, A2)> : Base
{
using Base::operator();
static int const index = Base::index - 1;
R operator()(A0 a0, A1 a1, A2 a2) const
{
return get<index>(static_cast<Derived
const*>(this)->functions)(a0, a1, a2);
}
};
template <typename Seq>
struct overload;
namespace detail
{
template <typename Seq, typename derived, int n, int size>
struct do_compose
{
typedef typename Seq::head_type head;
typedef typename Seq::tail_type tail;
typedef typename do_compose<tail, derived, n - 1, size>::type ov;
typedef overload_function<ov, derived, head> type;
};
template <typename Seq, typename derived, int size>
struct do_compose<Seq, derived, 1, size>
{
typedef typename Seq::head_type head;
typedef overload_function<final_overload_function<size>, derived,
head> type;
};
template <typename Seq>
struct compose_overload_base
{
enum { n = tuples::length<Seq>::value };
typedef overload<Seq> derived;
typedef typename do_compose<Seq, derived, n, n>::type type;
};
}
template <typename Seq>
struct overload : detail::compose_overload_base<Seq>::type
{
typedef typename tuples::element<0, Seq>::type Sig0;
typedef typename tuples::element<1, Seq>::type Sig1;
typedef typename tuples::element<2, Seq>::type Sig2;
typedef typename tuples::element<3, Seq>::type Sig3;
typedef
tuple<
boost::function<Sig0>
, boost::function<Sig1>
, boost::function<Sig2>
, boost::function<Sig3>
>
functions_type;
template <int N, typename F>
void set(F const& f)
{
get<N>(functions) = f;
}
functions_type functions;
};
}
#endif
And the test is:
/*=============================================================================
Copyright (c) 2006 Joel de Guzman
Use, modification and distribution is subject to the Boost Software
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
==============================================================================*/
#include <string>
#include <iostream>
#include "overload.hpp"
#include <boost/detail/lightweight_test.hpp>
int foo1(char)
{
return 123;
}
double foo2(int, char)
{
return 123.456;
}
char foo3(std::string)
{
return 'x';
}
void foo4(std::string s1, std::string s2, std::string s3)
{
std::cout << s1 << s2 << s3 << std::endl;
}
int main()
{
typedef boost::tuple<
int(char)
, double(int, char)
, char(std::string)
, void(std::string, std::string, std::string)
>
Signatures;
boost::overload<Signatures> f;
f.set<0>(&foo1);
f.set<1>(&foo2);
f.set<2>(&foo3);
f.set<3>(&foo4);
int i = f('x');
double d = f(123, 'x');
char c = f("hello");
f("Hello", ", World", ", I'm Joel");
BOOST_ASSERT(i == 123);
BOOST_ASSERT(d > 123.455 && d < 123.457);
BOOST_ASSERT(c == 'x');
return boost::report_errors();
}
It compiles and works for me.
Thanks
Marco
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk