
On Tue, 02 Oct 2007 01:52:51 +0200, Joel de Guzman <joel@boost-consulting.com> wrote:
As I said in my other post, it's better not to rely on mpl or fusion for low level libs like this. I gave a proof of concept. The challenge is to make it complete. The ideal is to:
1) Not rely on any libraries at all except boost.function whereby making it trim and clean (it's ok to use Boost PP**). Yep, you can get rid of the need for tuples, but if that makes it too painful, I guess it's ok to use it. It's a fairly simple class anyway. 2) Another challenge is to make it usable on as many compilers as possible. The first ideal is more important that this one. Perhaps it's ok to forget antiquated compilers without partial specialization, etc.
(**You'll still have to expand the overload_function(s) for N arguments, where N is the maximum the library can handle)
As Marco Costalba, I worked a little on a possible extension of boost::function in order to support overloading. Just a simple example: int foo1(char ) { return 123; } double foo2(int, char) { return 123.456; } int main() { overload<int(char ), double(int, char )> f; f.set( &foo1 ); f.set( &foo2 ); int i = f('x'); double d = f(123, 'x'); BOOST_ASSERT(i == 123); BOOST_ASSERT(d > 123.455 && d < 123.457); return 0; } My implementation relies on recursive inheritance of structs that inherit directly from boost::function. In this way I get function arguments automatically managed. However it is not based on tuples but it uses BOOST_PP_* macros and some utility from boost traits library. The nicest feature, IMO, is that in the most of the cases there isn't the need to specify indeces in order to set an overload: the signature is deduced from the type of the passed functor and used for setting the correct boost::function enclosed object. The max number of supported overloads is defined through a configurable macro and the max number of function arguments is the same available in the boost function library. At present the implementation of the overload class provides: (1) Several constructors and methods to set overload functions which can be used with any number (i.e. <= BOOST_OVERLOAD_LIMIT) of parameters and that relies on signature deduction. The kinds of handled functors are: -function pointers -pointers to member function -function objects -function object wrapped with boost::ref. The functors can be passed in any order. overload<sig1_t, sig2_t> f; f.set(&foo2, &foo1) However overloaded and polymorfic function objects are *not* handled, by these interface functions. (2) It's for this reason that I implemented also two template methods for setting an overload: one based on indices, and another based on signatures: overload<sig1_t, sig2_t> f; f.set<0>(&foo1); f.set<sig2_t>(&foo2); (3) As in the boost function library swap, empty and clear methods, are provided, moreover there is a get method in order to obtain a (const) reference to a specific boost function which belongs to the overload. See the example: void foo(std::string s1, std::string s2, std::string s3) { std::cout << s1 << s2 << s3 << std::endl; } [snip] // .... inside main: typedef void sig2_t (std::string , std::string , std::string ); sig2_t* f2 = &foo; boost::overload<sig1_t, sig2_t, sig3_t, sig4_t> f; [snip] f.set(f2); f( "Hello", ", ", "world !" ); f.clear<sig2_t>(); // same as f.clear<1>() BOOST_ASSERT( f.empty<sig2_t>() ); // same as f.empty<1>() boost::function<sig2_t> g(f2); f.swap_function(g); f("I'm ", "back ", "again !"); BOOST_ASSERT( g.empty() ); g = f.get<sig2_t>(); // same as f.get<1>() g("That's ", "all ", "folks !"); The empty, clear and get methods are available in two flavours: signature based and index based (index start from 0). The swap_function method works only with boost::function objects. (4) Some utility for type information : typedef boost::overload<sig1_t, sig2_t, sig3_t> overload_type; BOOST_STATIC_ASSERT(( overload_type::has_signature<sig_t1>::value )); BOOST_STATIC_ASSERT(( is_same<overload_type::signature<2>::type, sig3_t>::value )); How do you find the interface: confortable or confusing ? At present stage I've kept methods name as simple as possible and coherent with the ones used in boost::function. If you find them too generic I could append a _overload or _function suffix but better ideas are welcome. In the attached file there is an implementation of the overload class, you should consider it as a start point for discussion. Indeed the implementations are two: in the first I deduce function object signature by exploiting template function argument deduction, if the signature is not discovered no error is reported, and error handling is demanded to boost::function at call time; signature deduction of overloaded and polymorfic function objects cause an "unresolved overloaded function type" compile error; in the second implementation, with more template metaprogramming I succeed in deducing function object signature using only template classes; if the signature is not deduced a compile time error is produced; if this behavior is not desirable I can remove it, or turn it in a user controllable feature; signature deduction of overloaded and polymorfic function objects is successfull if it exists one and only one signature registered in the overload that matches with the function object, else an ad-hoc compile time error, pointing out the ambiguity, is produced. I tested both implementations with gcc 4.1.2 under Linux. Your opinions on pro and cons of the two implementations would be most appreciated. I'd like to know if the boost community finds such an extension of the boost function library worthwhile and useful, and if you consider the proposed implementation a sensible approach. Regards, Marco Cecchetti -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/