Runtime Dynamic Dispatch Library (0.2)

Hi Everyone, This version of the Dispatcher uses Boost.Fusion and Boost.Function. It also contains the strategized_map template (and test) which is basically an associative container which allows you to strategize the index validation and routing of the index. The strategized_map though is currently undocumented, though the unit tests already provide hints on how to use it. This release has been tested on Linux with GCC version 4.1.2 and Windows with MSVC 8.0 (Visual C++ 2005) against Boost's Subversion trunk. Comments and suggestions would be most appreciated. Please feel free to download the package(s) from Sourceforge: http://tinyurl.com/2cbzyl Or from the Boost Vault: http://tinyurl.com/24m2y2 This still does not implement the multiple-signature feature which I'm still contemplating on putting in, but this is already useful by itself. Please let me know if you would like to see some more compelling features you'd like to see in this library so that I can put them in before I formally submit it for review. Those who want to help cleaning up the code (and maybe doing some funky pre-processor programming) and implementing more features are welcome -- please let me know so that I can grant you write access to the subversion repository at Sourceforge. Have a great weekend everyone! -- Dean Michael C. Berris Software Engineer, Friendster, Inc. [http://cplusplus-soup.blogspot.com/] [mikhailberis@gmail.com] [+63 928 7291459] [+1 408 4049523]

On 9/30/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
Hi Everyone,
Hi Dean,
Comments and suggestions would be most appreciated.
Very nice work. I have found a lot of things are very similar to my simple_factory, especially now that has been ported to boost::fusion. But your code is more well organized, although I find it a little bit difficult for me, as example is not clear to me the whole part regarding the invokers, indeed from your example code void function(int argument) { // do something; }; //... dispatch::dispatcher<void (int), int> d; d[0] = function; //... int input; std::cin >> input; d[0](input); is not clear to me when and where this invokers are called given that dispatcher::operator[] returns a function object reference. Or perhaps I misread. One very little point is why you use default template parameters here; template <typename Signature, typename IndexType = int, typename DecisionStrategy = boost::dispatch::detail::always_true<IndexType>, typename RoutingStrategy = boost::dispatch::detail::default_routing<IndexType> > struct registry_impl If it is instantiated only from here: template <typename Signature, typename IndexType = int, typename DecisionStrategy = boost::dispatch::detail::always_true<IndexType>, typename RoutingStrategy = boost::dispatch::detail::default_routing<IndexType> > struct dispatcher : public boost::dispatch::detail::registry_impl <Signature, IndexType, DecisionStrategy, RoutingStrategy > where default parameters are already set.
This still does not implement the multiple-signature feature which I'm still contemplating on putting in, but this is already useful by itself.
Once I have grasped more with your code would be nice to add this part, or possibly to share your opinion on how to do it. As example simple_factory uses a multimap to achieve this. But the most difficult part is to allow "relaxed" type checking on function arguments. As example void function(int& counter) { counter++; }; //... dispatch::dispatcher<void (int&), int> d; d[0] = function; //... int input = 6; d[0](input); std::cout << input << "\n"; // should be 7 now. This is difficult with multiple-signature feature. I have implemented this in simple_factory, but was not straightforward and I doubts my approach is the best possible one, so I would really like to share your implemantation ideas on this. Thanks Marco

Hi Marco! On 9/30/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 9/30/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
Comments and suggestions would be most appreciated.
Very nice work. I have found a lot of things are very similar to my simple_factory, especially now that has been ported to boost::fusion.
Thank you very much. I do my best. :)
But your code is more well organized, although I find it a little bit difficult for me, as example is not clear to me the whole part regarding the invokers, indeed from your example code
void function(int argument) { // do something; };
//... dispatch::dispatcher<void (int), int> d; d[0] = function;
//... int input; std::cin >> input; d[0](input);
is not clear to me when and where this invokers are called given that dispatcher::operator[] returns a function object reference. Or perhaps I misread.
Can you refer to which page in the documentation you see that? The invoker is intended to be used this way: (Refers to documentation page on Invoker in the Library Design section) boost::dispatch::dispatcher<void ()> void_dispatcher; boost::dispatch::invoke_(void_dispatcher)() << 0 << 1 << 2; The inoke_(void_dispatcher)() returns a callable object, which encapsulates a reference to the dispatcher instance. The operator<<'s allow you to pass indexes to this callable invoker object, which are used in indexing the dispatcher using the operator[] definition for the particular dispatcher. Invokers are useful if you want to write functions which take in a reference to an existing dispatcher, and then specify some sort of invocation sequence with an easier interface. Example would be: template <class DispatcherType, class InputType> void setup_sequence(DispatcherType & dispatcher, InputType const & input) { try { enum { INIT, CONNECT, REQUEST, DISCONNECT, PROCESS }; boost::dispatch::invoke_(dispatcher)(input) << INIT << CONNECT << REQUEST << DISCONNECT << PROCESS; } catch (boost::dispatch::unregistered_handler & e) { // fail gracefully? }; };
One very little point is why you use default template parameters here;
template <typename Signature, typename IndexType = int, typename DecisionStrategy = boost::dispatch::detail::always_true<IndexType>, typename RoutingStrategy = boost::dispatch::detail::default_routing<IndexType> > struct registry_impl
If it is instantiated only from here:
template <typename Signature, typename IndexType = int, typename DecisionStrategy = boost::dispatch::detail::always_true<IndexType>, typename RoutingStrategy = boost::dispatch::detail::default_routing<IndexType> > struct dispatcher : public boost::dispatch::detail::registry_impl <Signature, IndexType, DecisionStrategy, RoutingStrategy >
where default parameters are already set.
Yes, good observation. Actually this is a remnant of a refactoring I performed a couple of releases back. This also allows anyone (currently, just me) to extend the dispatcher concept to use a different back-end implementation with minimal disruption. But generally, the template defaults are just there -- they don't hurt anyone really. ;-)
This still does not implement the multiple-signature feature which I'm still contemplating on putting in, but this is already useful by itself.
Once I have grasped more with your code would be nice to add this part, or possibly to share your opinion on how to do it. As example simple_factory uses a multimap to achieve this.
But the most difficult part is to allow "relaxed" type checking on function arguments. As example
void function(int& counter) { counter++; };
//... dispatch::dispatcher<void (int&), int> d; d[0] = function;
//... int input = 6; d[0](input);
std::cout << input << "\n"; // should be 7 now.
This is difficult with multiple-signature feature. I have implemented this in simple_factory, but was not straightforward and I doubts my approach is the best possible one, so I would really like to share your implemantation ideas on this.
The immediate "top of my head" implementation would be to do a linear inheritance of the different Functor objects that support different signatures to represent a multi-signature Functor wrappers. If you will endulge, the concept is pretty simple (though not really straight forward to implement without using help from Boost.Fusion/Boost.MPL): typedef dispatcher< signatures<void(int), void(double), void(string)>
multi_index_dispatcher;
multi_index_dispatcher will then contain Functor objects of the form: struct Functor<void(double)> : Functor<void(string)> { }; struct Functor<void(int)> : Functor<void(double)> { }; and the result will be a Functor<void(int)> that inherits from Functor<void(double)> that inherits from Functor<void(string)> -- I believe this can be implemented with Boost.Fusion/MPL `fold`, how I'm not entirely sure yet. But the resulting type will have operator() overloads of different signatures -- which signature is chosen is determined at compile time. So given the above and then the following: void foo(double d) ; void bar(string s) ; void fizz(int i) ; multi_index_dispatcher d; d[0] = foo; // valid, will register the void(double) d[0] = bar; // valid, will register the void(string) d[0] = fizz; // valid, will register the void(int) d[0](1.0); // valid, will call the void(double) d[0](1); // valid, will call the void(int) d[0]("1"); // valid, will call the void(string) This might also be achievable with an encapsulated Fusion map instead of linear inheritance, but I'm not entirely sure about being able to generate the appropriate type-safe operator() overloads in that manner.
Thanks Marco
Thank you for the interest, and I definitely hope the above explanation helps. :) -- Dean Michael C. Berris Software Engineer, Friendster, Inc. [http://cplusplus-soup.blogspot.com/] [mikhailberis@gmail.com] [+63 928 7291459] [+1 408 4049523]

On 9/30/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
is not clear to me when and where this invokers are called given that dispatcher::operator[] returns a function object reference. Or perhaps I misread.
Can you refer to which page in the documentation you see that?
If you mean the above example is in: dispatcher-0.2/libs/dispatcher/doc/index.html
The invoker is intended to be used this way:
Thanks, now it's much more clear.
The immediate "top of my head" implementation would be to do a linear inheritance of the different Functor objects that support different signatures to represent a multi-signature Functor wrappers.
--------- cut ---------------
void foo(double d) ; void bar(string s) ; void fizz(int i) ;
multi_index_dispatcher d; d[0] = foo; // valid, will register the void(double) d[0] = bar; // valid, will register the void(string) d[0] = fizz; // valid, will register the void(int)
Also Dispatcher::operator=() should be 'stacked' in some way though...but how?
d[0](1.0); // valid, will call the void(double) d[0](1); // valid, will call the void(int) d[0]("1"); // valid, will call the void(string)
This might also be achievable with an encapsulated Fusion map instead of linear inheritance, but I'm not entirely sure about being able to generate the appropriate type-safe operator() overloads in that manner.
Perhaps if the key of the map is the function signature could be possible first find a match with the supplied arguments and then call the operator(), should be safe in that case. A (big) downside is that you forget implicit conversions this way.
Thank you for the interest, and I definitely hope the above explanation helps. :)
Helped a lot. Thanks Marco

On 9/30/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 9/30/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
is not clear to me when and where this invokers are called given that dispatcher::operator[] returns a function object reference. Or perhaps I misread.
Can you refer to which page in the documentation you see that?
If you mean the above example is in: dispatcher-0.2/libs/dispatcher/doc/index.html
Ah, this documentation is I think a bit dated -- and is one of the earlier attempts at defining what the dispatcher is supposed to look like. Please refer to the generated documentation in dispatcher-0.2/libs/dispatcher/doc/html/index.html -- at least it's prettier, and is more hierarchically coherent (or so i think. ;) ).
The immediate "top of my head" implementation would be to do a linear inheritance of the different Functor objects that support different signatures to represent a multi-signature Functor wrappers.
--------- cut ---------------
void foo(double d) ; void bar(string s) ; void fizz(int i) ;
multi_index_dispatcher d; d[0] = foo; // valid, will register the void(double) d[0] = bar; // valid, will register the void(string) d[0] = fizz; // valid, will register the void(int)
Also Dispatcher::operator=() should be 'stacked' in some way though...but how?
Remember that operator=() can be implemented as part of the class -- and it can be overloaded much like the other operators. That means: Functor<void(int)> has: Functor<void(int)> & operator=(boost::function<void(int)> const & function) { this->_wrapped_function = function; return *this; }; Function<void(double)> has: Functor<void(double)> & operator=(boost::function<void(double)> const & function) { this->_wrapped_function = function; return *this; }; And since it's linear inheritance, the derived type (or at least the one in the end of the inheritance hierarchy) will inherit all these overloads to operator=() which will enable the compiler to choose at compile time which overload it's going to use depending on what's on the right hand side of the operator=().
d[0](1.0); // valid, will call the void(double) d[0](1); // valid, will call the void(int) d[0]("1"); // valid, will call the void(string)
This might also be achievable with an encapsulated Fusion map instead of linear inheritance, but I'm not entirely sure about being able to generate the appropriate type-safe operator() overloads in that manner.
Perhaps if the key of the map is the function signature could be possible first find a match with the supplied arguments and then call the operator(), should be safe in that case. A (big) downside is that you forget implicit conversions this way.
This is one problem with the Fusion map approach, but something I perceive as really a non-issue -- because after all, the goal of the library is to provide a type-safe way of implementing a dispatcher. However, I find that your requirement for implicit type conversion is something I particularly don't find very compelling since I'd rather have at compile time (or statically) know that I'm performing a conversion -- with static_cast<> or copy construction -- instead of the compiler doing it for me. I think allowing for implicit conversions is very dangerous and contrary to the notion of type-safety -- but don't let that stop you from implementing it and making it a design goal. It's just how I see it, which you can safely ignore. :)
Thank you for the interest, and I definitely hope the above explanation helps. :)
Helped a lot.
I'm glad it helped. :)
Thanks Marco
You're welcome. :) -- Dean Michael C. Berris Software Engineer, Friendster, Inc. [http://cplusplus-soup.blogspot.com/] [mikhailberis@gmail.com] [+63 928 7291459] [+1 408 4049523]

On 9/30/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
Also Dispatcher::operator=() should be 'stacked' in some way though...but how?
Remember that operator=() can be implemented as part of the class -- and it can be overloaded much like the other operators. That means:
I see.
Perhaps if the key of the map is the function signature could be possible first find a match with the supplied arguments and then call the operator(), should be safe in that case. A (big) downside is that you forget implicit conversions this way.
This is one problem with the Fusion map approach, but something I perceive as really a non-issue -- because after all, the goal of the library is to provide a type-safe way of implementing a dispatcher.
On the other way a dispatcher as long as feeds arguments to a wrapped-in function is natural IMHO asking to act as transparent as possible between the argument values and the target function, i.e. should be a perfect forwarder once target function has been selected among the stored set. Under this view if a function void foo(std::string v); can be invoked with foo("test"); so should (IMHO) accept the foo wrapper and, at the end, the dispatcher that stores the wrapper. Just a questionable opinion ;-) Marco

On 9/30/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 9/30/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
Perhaps if the key of the map is the function signature could be possible first find a match with the supplied arguments and then call the operator(), should be safe in that case. A (big) downside is that you forget implicit conversions this way.
This is one problem with the Fusion map approach, but something I perceive as really a non-issue -- because after all, the goal of the library is to provide a type-safe way of implementing a dispatcher.
On the other way a dispatcher as long as feeds arguments to a wrapped-in function is natural IMHO asking to act as transparent as possible between the argument values and the target function, i.e. should be a perfect forwarder once target function has been selected among the stored set.
Under this view if a function
void foo(std::string v);
can be invoked with
foo("test");
so should (IMHO) accept the foo wrapper and, at the end, the dispatcher that stores the wrapper. Just a questionable opinion ;-)
I don't think we're using the same terms here: the dispatcher is the container that contains the function wrappers. The function wrappers on the other hand, may be implemented to have multiple overloads using a linear inheritance technique to overload operator= and operator() which the compiler chooses statically which overload will be included. The other more important problem with using an encapsulated Fusion map, is that the only way the lookup is going to happen is through a member template function with tons of overloads to support multiple cases -- not to mention running into the forwarding problem which has all but been beaten to death already with such libraries as Boost.Bind among others. The implicit conversion you talk about will not be present in the linear inheritance approach I've mentioned earlier. If Functor<> contained a fusion map of the signatures and the actual wrapped function, the only way it [the Functor<>] can determine which implementation to choose is by doing something like this: template <...> struct Functor { fusion::map< fusion::pair<RT1(T1, T2, ..., TN), boost::function<RT1(T1, T2, ..., TN)> >, fusion::pair<RT2(Tt1, Tt2, ..., TtN), boost::function<RT2(Tt1, Tt2, ..., TtN)> > ...
;
template <T1, T2, T3, T4, ..., TN> ReturnType operator()(T1 const & arg1, T2 const & arg2, ..., TN const & argn) { return fusion::invoke( fusion::at_key<ReturnType(T1, T2, ..., TN)>(_fusion_map), fusion::make_tuple(T1, T2, ..., TN) ); }; }; Which is messy, and doesn't solve the implicit conversion problem you're facing either. So the only alternative really (or at least the one I see that doesn't run into the forwarding problem) is the linear inheritance approach I've been mentioning. Now getting towards implementing that approach is another discussion and effort in itself -- one I'm still mulling around if it's even worth pursuing, given the cases I intend to cover with the dispatcher. If at all possible, even an enhancement to Boost.Function might be handy which will allow it to contain function pointers to multiple signatures -- but I'm not that ambitious (yet) to try and hack at Boost.Function to enable multiple signature support and compile-time dispatching based on argument type lookup. That might be something worth looking at, but that I think is a battle I rather not fight today -- or at least not yet. :) I think we're agreed that the Fusion map is not the best way to approaching a solution to this problem, so please read the explanation above as a reasoning as to why I think this is so -- and why I think the implicit conversion is a non-issue compared to the forwarding problem faced by such an approach. Maybe there's a simplification of the problem by using a Fusion tuple, and doing some template metaprogramming to find which Boost.Function member is most suitable given a forwarding operator() implementation, but I can't wrap my head around that just yet. At any rate, I'm thinking maybe this multiple signature Function wrapper thing is way too much work for little utility -- at the same time I think it's a challenge worth tackling FWIW. HTH :) -- Dean Michael C. Berris Software Engineer, Friendster, Inc. [http://cplusplus-soup.blogspot.com/] [mikhailberis@gmail.com] [+63 928 7291459] [+1 408 4049523]

Dean Michael Berris wrote:
So the only alternative really (or at least the one I see that doesn't run into the forwarding problem) is the linear inheritance approach I've been mentioning. Now getting towards implementing that approach is another discussion and effort in itself -- one I'm still mulling around if it's even worth pursuing, given the cases I intend to cover with the dispatcher. If at all possible, even an enhancement to Boost.Function might be handy which will allow it to contain function pointers to multiple signatures -- but I'm not that ambitious (yet) to try and hack at Boost.Function to enable multiple signature support and compile-time dispatching based on argument type lookup.
I think I've mentioned that I have such a "overloads" library extension in my HD somewhere. At one point, I asked Doug on the possibility of adding it to boost.function and he expressed his interest. Of course that means documentation and stuff. I'll try to see if I can squeeze some time to get this into completion. At any rate, I can post the code sans docs. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
Dean Michael Berris wrote:
So the only alternative really (or at least the one I see that doesn't run into the forwarding problem) is the linear inheritance approach I've been mentioning. Now getting towards implementing that approach is another discussion and effort in itself -- one I'm still mulling around if it's even worth pursuing, given the cases I intend to cover with the dispatcher. If at all possible, even an enhancement to Boost.Function might be handy which will allow it to contain function pointers to multiple signatures -- but I'm not that ambitious (yet) to try and hack at Boost.Function to enable multiple signature support and compile-time dispatching based on argument type lookup.
I think I've mentioned that I have such a "overloads" library extension in my HD somewhere. At one point, I asked Doug on the possibility of adding it to boost.function and he expressed his interest. Of course that means documentation and stuff. I'll try to see if I can squeeze some time to get this into completion. At any rate, I can post the code sans docs.
[CC'ing Doug] Ok, here's the proof of concept: http://spirit.sourceforge.net/dl_more/overload/ Here's the original text I sent Doug: Boost.function is a very useful library for wrapping function objects. Yet, one limitation it has, compared to generic function objects, is that it is monomorphic. It has a specific fixed signature and is unusable polymorphically. One particular case it can't be used for, for example, is as a visitor for boost variant. But that view is minimalistic. I don't think I need to expound on the virtues of overloaded functions. But, let me show some examples anyway... Say we have a boost.function named "concat". It can be called much like any function. For example: concat(str, str2) Boost.function has a fixed signature. For example, "concat" can be declared as: function<std::string(std::string, std:string)> Now here lies the problem... But, I'd like to also allow: concat(str, 'x') concat(str, "Hi") concat("Hi", str) concat('x', str) or possibly even: concat("Hi", ", World") concat('x', 'y') Unfortunately, we can't use boost.function like that because it is monomorphic. (Sure, "Hi" can be implicitly converted to a std::string, but a temporary will have to be created. We are out of luck for 'x': there is no implicit conversion). 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: boost::overload< std::string(std::string, std:string) , std::string(std::string, char) , std::string(std::string, char const*) , std::string(char, std::string) , std::string(char const*, std::string) > concat; Since "concat" is polymorphic, its declaration can be extended to also support wide strings. Sure, you can have different return types! Also, we are not limited to 2 argument overloads. We can also allow: concat(str, cstr, len) [...end concat example...] Now, for Spirit, what I wanted to do, for a long time now, is reduce the Spirit "rule" to a boost.function. Yet, as of Spirit 1.8, I found that it is not possible to use boost.function as-is because its "rule" can be parameterized to take in a couple of scanner types (e.g. one with space-skipping, one without): r.parse(plain-scanner); r.parse(skip-scanner); With the proposed overload extension, I can now do that. Here's Doug's reply: Very cool. This is one of those "... you don't need it often, but when you need it you *really* need it" features. If you're interested in finished it up, I'd be happy to put it straight into the Function library. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

On 10/1/07, Joel de Guzman <joel@boost-consulting.com> 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:
boost::overload< std::string(std::string, std:string) , std::string(std::string, char) , std::string(std::string, char const*) , std::string(char, std::string) , std::string(char const*, std::string) > concat;
Or possibly (perhaps) typedef fusion::vector< std::string(std::string, std:string) , std::string(std::string, char) , std::string(std::string, char const*) , std::string(char, std::string) , std::string(char const*, std::string) > overloads_sequence; boost::overload<overloads_sequence> concat; Just one question. Is it possible, given a class T to deduce its implicit convrsions? As example class A { A(); A(const A&) ; A(int); explicit A(double); }; typedef implicit_conversions<A> implicits; where 'implicits' is, as example, fusion::vector<void, int, double, const A&> Thanks Marco

On 9/30/07, Marco Costalba <mcostalba@gmail.com> wrote:
Just one question. Is it possible, given a class T to deduce its implicit convrsions?
As example
class A { A(); A(const A&) ; A(int); explicit A(double); };
typedef implicit_conversions<A> implicits;
where 'implicits' is, as example, fusion::vector<void, int, double, const A&>
I don't think there is even a facility in C++ which allows for even static type introspection without querying for actual members of a type. I might be wrong though. -- Dean Michael C. Berris Software Engineer, Friendster, Inc. [http://cplusplus-soup.blogspot.com/] [mikhailberis@gmail.com] [+63 928 7291459] [+1 408 4049523]

On 10/1/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 10/1/07, Joel de Guzman <joel@boost-consulting.com> 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:
boost::overload< std::string(std::string, std:string) , std::string(std::string, char) , std::string(std::string, char const*) , std::string(char, std::string) , std::string(char const*, std::string) > concat;
Or possibly (perhaps)
typedef fusion::vector< std::string(std::string, std:string) , std::string(std::string, char) , std::string(std::string, char const*) , std::string(char, std::string) , std::string(char const*, std::string) > overloads_sequence;
boost::overload<overloads_sequence> concat;
As example changing the inheritance compositing structure from namespace detail { template <typename Sig0, typename Sig1, typename Sig2, typename Sig3> struct compose_overload_base { typedef overload<Sig0, Sig1, Sig2, Sig3> derived; typedef overload_function<final_overload_function, derived, Sig0> ov1; typedef overload_function<ov1, derived, Sig1> ov2; typedef overload_function<ov2, derived, Sig2> ov3; typedef overload_function<ov3, derived, Sig3> ov4; typedef ov4 type; }; } to namespace detail { template <typename Seq, typename derived, int n> struct do_compose { typedef typename fusion::result_of::value_at_c<Seq, n - 1>::type sig; typedef typename fusion::result_of::pop_back<Seq>::type popped_seq; typedef do_compose<popped_seq, derived, n - 1> ov; typedef overload_function<ov, derived, sig> type; }; template <typename Seq, typename derived> struct do_compose<Seq, derived, 1> { typedef typename fusion::result_of::value_at_c<Seq, 0>::type sig; typedef overload_function<final_overload_function, derived, sig> type; }; template <typename Seq> struct compose_overload_base { enum { n = fusion::result_of::size<Seq>::type::value }; typedef overload<Seq> derived; typedef typename do_compose<Seq, derived, n>::type type; }; } A little bit more complex but works for any number of arguments (sigantures). Marco

Marco Costalba wrote:
On 10/1/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 10/1/07, Joel de Guzman <joel@boost-consulting.com> 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 :-) Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

On 10/1/07, Joel de Guzman <joel@boost-consulting.com> wrote:
Marco Costalba wrote:
On 10/1/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 10/1/07, Joel de Guzman <joel@boost-consulting.com> 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

I wanted to add the final touch, from :
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;
to namespace detail { struct get_function { template <typename T> struct apply { typedef boost::function<T> type; }; }; } template <typename Seq> struct overload : detail::compose_overload_base<Seq>::type { typedef typename boost::mpl:: transform<Seq, detail::get_function>::type functions_type; But i have a strange compile error. [snip] overload.cpp:45: instantiated from here boost_dir/boost/mpl/clear.hpp:31: error: invalid use of incomplete type 'struct boost::mpl::clear_impl<boost::mpl::non_sequence_tag>::apply<boost::tuples::tuple<int ()(char), double ()(int, char), char ()(std::string), v [snip] I have included #include <boost/mpl/transform.hpp> but proabbly I'm missing something... Could someone help me? I'm new to boost. Thanks Marco

Marco Costalba wrote:
I wanted to add the final touch, from :
[snip]
But i have a strange compile error.
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) Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

On 10/2/07, Joel de Guzman <joel@boost-consulting.com> wrote:
Marco Costalba wrote:
I wanted to add the final touch, from :
[snip]
But i have a strange compile error.
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:
Ok. I will try to code something "manually" ;-)
(**You'll still have to expand the overload_function(s) for N arguments, where N is the maximum the library can handle)
Yes. I left it as the last one because probably will be unsuccessful to find a template only way to expand overoload_functions(s) without repetition, and without preprocessor macros. For the very few I know boost, the code I've looked at in the libraries it seems that in this cases the accepted way is to rely on preprocessor. But for my untrained eye is still difficult to read such a code. And for my untrained sense of aesthetic I would call that code a little bit on the ugly side. I, perhaps strange enough, still prefer to see the whole set of repetitions instead of one packed BOOST macro stuff block. Marco

Marco Costalba wrote:
(**You'll still have to expand the overload_function(s) for N arguments, where N is the maximum the library can handle)
Yes. I left it as the last one because probably will be unsuccessful to find a template only way to expand overoload_functions(s) without repetition, and without preprocessor macros.
For the very few I know boost, the code I've looked at in the libraries it seems that in this cases the accepted way is to rely on preprocessor.
But for my untrained eye is still difficult to read such a code. And for my untrained sense of aesthetic I would call that code a little bit on the ugly side. I, perhaps strange enough, still prefer to see the whole set of repetitions instead of one packed BOOST macro stuff block.
Ok, your call, since you're the one taking the challenge anyway :) Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Suggestion (and implementation) of 3 filesystem functions wich we have used a lot on the C++ documentation tool DoxyS (Doxygen spin off, www.doxys.dk). Well, enough intro. The functions are: [intersection_from_start ( path1, path2)]: Get common part of the two from the start. Returs the intersection/common-part (from the root and forward) of the two paths. [remove_from_start (inPath, remPath) ]: Remove part of path from beginning. Returns inPath with the intersection of inPath and remPath removed. [relative_path ( pathFrom, fileTo ) ]: Returns relative path from dir to file/dir. Implementation: ----------------------------------------------------------------------------------------- /** Get common part of the two from the start. Finds the intersection of two parts from the beginning of the paths. See the example below. \return The intersection/common-part (from the root and forward) of the two paths. \example namespace fs = boost::filesystem; fs::path path1("z:/hello/horse/goat/pig/cow/sheep", fs::native); fs::path path2("z:/hello/horse/whale/dolphin", fs::native); intersection_from_start(inPath, remPath) == fs::path("z:/hello/horse"); \endexample */ boost::filesystem::path intersection_from_start( const boost::filesystem::path& path1, ///< [in] Path 1 const boost::filesystem::path& path2 ///< [in] Path 2 ) { namespace fs = boost::filesystem; fs::path::iterator it1 = path1.begin(); fs::path::iterator it2 = path2.begin(); if ( *it1 != *it2 ) { assert(*it1 == *it2 ); return fs::path(); // If path do not have same root, return an empty path !!! } fs::path intersectionPath; while ( (it1 != path1.end()) && (it2 != path2.end()) && (*it1 == *it2)) { intersectionPath /= fs::path(*it1, fs::native); ++it1; ++it2; } return intersectionPath; } /** Remove part of path from beginning. See the example below. If paths does not have the same root then inPath is returned. \return inPath with the intersection of inPath and remPath removed. \example namespace fs = boost::filesystem; fs::path inPath("z:/hello/horse/goat/pig/cow/sheep", fs::native); fs::path remPath("z:/hello/horse", fs::native); remove_from_start(inPath, remPath) == fs::path("goat/pig/cow/sheep"); \endexample */ boost::filesystem::path remove_from_start( const boost::filesystem::path& inPath, ///< [in] Path to remove start of path from const boost::filesystem::path& remPath ///< [in] Path to remove from inPath ) { namespace fs = boost::filesystem; fs::path::iterator itIn = inPath.begin(); fs::path::iterator itRem = remPath.begin(); if ( *itIn != *itRem ) { // assert(*itIn == *itRem ); return inPath; // If path do not have same root, just return inPath !!! } while ((itIn != inPath.end()) && (itRem != remPath.end()) && (*itIn == *itRem) ) { ++itIn; ++itRem; } fs::path outPath; for ( ;itIn != inPath.end(); ++itIn ) { outPath /= fs::path(*itIn, fs::native); // fs::native so we can cope with spaces in file names } return outPath; } /** Make relative path from dir to file/dir. Use this function to make a relative link to a file in one directory, from a given directory. Typically one has an absolute from path (no filename only path) and an absolute path to the file to link to (path and filename). See examples. \return Relative path from pathFrom to fileTo. \example namespace fs = boost::filesystem; fs::path linkFrom("z:/hello/horse/goat/pig/cow/sheep", fs::native); fs::path linkTo("z:/hello/horse/whale/dolphin/seal.txt", fs::native); relative_path(linkFrom, linkTo) == fs::path("../../../../whale/dolphin/seal.txt"); \endexample */ boost::filesystem::path relative_path ( const boost::filesystem::path& pathFrom, ///< [in] Path to link from. No file name only path. const boost::filesystem::path& fileTo ///< [in] Path/filename to link to. Path including the filename to link to. ) { namespace fs = boost::filesystem; fs::path::iterator itFrom = pathFrom.begin(); fs::path::iterator itTo = fileTo.begin(); if ( *itFrom != *itTo ) { assert(*itFrom == *itTo ); return fileTo; // If path do not have same root, just return "to path"!!! } while ( (itFrom != pathFrom.end()) && (itTo != fileTo.end()) && (*itFrom == *itTo) ) { ++itFrom; ++itTo; } fs::path relPath; for ( ;itFrom != pathFrom.end(); ++itFrom ) { relPath /= ".."; } for ( ;itTo != fileTo.end(); ++itTo) { relPath /= *itTo; } return relPath; } ----------------------------------------------------------------------------------------- -Martin Lutken

On 10/2/07, Joel de Guzman <joel@boost-consulting.com> wrote:
Ok, your call, since you're the one taking the challenge anyway :)
I have tried to remove the dependancy from mpl library and perhaps I have found a nice way to do it. The key idea is to use the deinitions of tuple<A, B, C, D> that is (perhaps) a cons<A, cons<B, cons<C, cons<D, null_type> > > > So instead of the following previous code: 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; }; struct get_function { template <typename T> struct apply { typedef boost::function<T> type; }; }; } template <typename Seq> struct overload : detail::compose_overload_base<Seq>::type { typedef typename boost::mpl:: transform<Seq, detail::get_function>::type functions_type; functions_type functions; }; I could write directly 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 do_compose<tail, derived, n - 1, size> next; typedef typename next::type ov; typedef typename next::cons cons_tail; typedef overload_function<ov, derived, head> type; typedef tuples::cons<boost::function<head>, cons_tail> cons; }; template <typename Seq, typename derived, int size> struct do_compose<Seq, derived, 1, size> { typedef typename Seq::head_type head; typedef final_overload_function<size> final; typedef overload_function<final, derived, head> type; typedef tuples::cons<head, tuple<> > cons; }; template <typename Seq> struct compose_overload_base : do_compose< Seq, overload<Seq>, tuples::length<Seq>::value, tuples::length<Seq>::value > {}; } template <typename Seq> struct overload : detail::compose_overload_base<Seq>::type { typedef detail::compose_overload_base<Seq> Base; typedef typename Base::cons functions_type; functions_type functions; // COMPILE ERROR HERE }; But I have an error as soon as I try to instantiate 'functions_type' The compile error seems very internal to tuple library and an help on how to come up with this would be very apreciated... Thanks a lot for your patience (I'm a newbie) Marco

On Tue, 02 Oct 2007 12:24:47 +0200, Marco Costalba <mcostalba@gmail.com> wrote: skip
I could write directly
skip
typedef overload_function<final, derived, head> type; typedef tuples::cons<head, tuple<> > cons; };
Maybe you should replace tuple<> with tuples::null_type ... skip
But I have an error as soon as I try to instantiate 'functions_type'
The compile error seems very internal to tuple library and an help on how to come up with this would be very apreciated...
... but I don't know if this is the only problem. However your last changes makes the code too complicated, IMO. I made up a metafunction called wrapper that should do the work. examples: (1) typedef tuple<int, double, char> fund_types; typedef wrapper<fund_types, vector>::type vectors; BOOST_STATIC_ASSERT(( is_same< vectors, cons<vector<int>, cons<vector<double>, cons<vector<char>, null_type > > > > )); (2) typedef tuple< int(char) , double(int, char) , char(std::string) > signatures; typedef wrapper<signatures, boost::function>::type functions; BOOST_STATIC_ASSERT(( is_same< functions, cons<function<int(char)>, cons<function<double(int, char)>, cons<function<char(std::string)>, null_type > > > > )); Here follow the code for the metafunction: namespace boost { namespace detail { template< typename Seq, template<typename > class TT, unsigned int N = tuples::length<Seq>::value
struct wrapper { typedef typename Seq::head_type head; typedef typename Seq::tail_type tail; typedef TT<head> new_head; typedef typename wrapper<tail, TT>::type new_tail; typedef tuples::cons< new_head, new_tail > type; }; template< typename Seq, template<typename > class TT> struct wrapper<Seq, TT, 0> { typedef tuples::null_type type; }; } } // end namespaces I used it inside the overload struct replacing the code: 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; with a single line : typedef typename detail::wrapper<Seq, boost::function>::type functions_type; ... and all seems to work correctly. I tested it with gcc 4.1.2 and boost 1.33.1 under linux. Moreover the wrapper metafunction can be used in other context too. The question is : it's ok to use cons< cons < ... >, ..., null_type > instead of tuple type ? Regards, Marco Cecchetti -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

On 10/2/07, Marco <mrcekets@gmail.com> wrote:
On Tue, 02 Oct 2007 12:24:47 +0200, Marco Costalba <mcostalba@gmail.com>
typedef overload_function<final, derived, head> type; typedef tuples::cons<head, tuple<> > cons; };
Maybe you should replace tuple<> with tuples::null_type ...
I have found the error! The problem was in typedef tuples::cons<head, tuple<> > cons; instead of typedef tuples::cons<boost::function<head>, cons_tail> cons; BTW I have pushed the product of this exercise: http://digilander.libero.it/mcostalba/boost_overload/overload.hpp http://digilander.libero.it/mcostalba/boost_overload/test.cpp I have added also some stuff to let user avoid messing with indices when he already has the functions ready to be assigned, so that he can do this directly from the overload c'tor, see the test file if the above line is not clear enough (and probably is not ;-)
The question is : it's ok to use cons< cons < ... >, ..., null_type > instead of tuple type ?
This is a good question. I don't know the answer. Marco

On 10/2/07, Marco <mrcekets@gmail.com> wrote:
However your last changes makes the code too complicated, IMO. I made up a metafunction called wrapper that should do the work.
Yes your metafunction is nice but I wanted to reuse the same 'do_compose' struct already used for getting the linear hineritance adding only a couple of lines (2 in the primary template, 1 in the specialization). Your is a general metafunction wrapper, my hack is very tailored for this task only. Marco

On Tue, 02 Oct 2007 21:15:06 +0200, Marco Costalba <mcostalba@gmail.com> wrote:
On 10/2/07, Marco <mrcekets@gmail.com> wrote:
However your last changes makes the code too complicated, IMO. I made up a metafunction called wrapper that should do the work.
Yes your metafunction is nice but I wanted to reuse the same 'do_compose' struct already used for getting the linear hineritance adding only a couple of lines (2 in the primary template, 1 in the specialization).
Your is a general metafunction wrapper, my hack is very tailored for this task only.
Marco
I see, I tested your code and it works fine. :-) In the meanwhile, I'm trying a different approach. I would like to be able to deduce the signature of a functor without the need of using index. example: int foo1(char ) { return 123; } double foo2(int, char) { return 123.456; } int main() { overload<int(char ), double(int, char )> f; f = &foo1; // no index needed f = &foo2; // the right assignment // is achieved by deducing // the argument signature int i = f('x'); double d = f(123, 'x'); BOOST_ASSERT(i == 123); BOOST_ASSERT(d > 123.455 && d < 123.457); return boost::report_errors(); } this is enough simple when the argument is a function pointer but can be more complex in other cases. I hope to be able to post some result, soon. Kind Regards, Marco Cecchetti -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

On 10/5/07, Marco <mrcekets@gmail.com> wrote:
In the meanwhile, I'm trying a different approach. I would like to be able to deduce the signature of a functor without the need of using index.
Interesting. Overloading on operator= as we did with operator() is the first thing it comes to my mind. I tried to hide the indices (that are really only implementation related) from the API using the constructor approach, but I think yours is more flexible.
int main() { overload<int(char ), double(int, char )> f;
Default class template parameters here ? ;-)
f = &foo1; // no index needed f = &foo2; // the right assignment // is achieved by deducing // the argument signature
overloading overload::operator=() perhaps ?
this is enough simple when the argument is a function pointer but can be more complex in other cases.
I'm really curious to see your code. Marco

On 10/5/07, Marco <mrcekets@gmail.com> wrote:
I hope to be able to post some result, soon.
Waiting for Marco's code I have updated the files at http://digilander.libero.it/mcostalba/boost_overload/overload.hpp http://digilander.libero.it/mcostalba/boost_overload/test.cpp Now operator<<() is used instead of c'tors, this has three advantages: - functions can be registered in any order - code is mcuh smaller - indices are really hidden now Current limitation is that it works with function's pointers, still not with functors, but I think the other Marco is probably taking care of it... ;-) Thanks Marco

On 10/6/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 10/5/07, Marco <mrcekets@gmail.com> wrote:
I hope to be able to post some result, soon.
Waiting for Marco's code I have updated the files at
http://digilander.libero.it/mcostalba/boost_overload/overload.hpp http://digilander.libero.it/mcostalba/boost_overload/test.cpp
Now operator<<() is used instead of c'tors, this has three advantages:
BTW the test example now looks like: int main() { typedef boost::tuple< int(char) , double(int, char) , char(std::string) , void(std::string, std::string, std::string) , int() > Signatures; boost::overload<Signatures> f; f << &foo2 << foo4 << foo3 << &foo1 << foo5; // in any order... int i = f('x'); double d = f(123, 'x'); char c = f("hello"); int k = f(); f("Hello", ", World", ", I'm Joel"); BOOST_ASSERT(i == 123); BOOST_ASSERT(d > 123.455 && d < 123.457); BOOST_ASSERT(c == 'x'); BOOST_ASSERT(k == 7); return boost::report_errors(); }

I haven't been following this thread, but my radar spotted this:
Now operator<<() is used instead of c'tors, this has three advantages:
Hmmm, someone else is tempted to invent yet another use for operator<< ? If we keep doing this, we'll end up with entire functions where everything is done using << and there are no alphabetic identifiers at all! In this case, compare f << &foo2 << foo4 << foo3 << &foo1 << foo5; with f.add_overload(&foo2); f.add_overload(foo4); f.add_overload(foo3); f.add_overload(&foo1); f.add_overload(foo5); The first version involves less typing. But, to someone who did not write the code, wouldn't it be reasonable to look at it and think that f is a file and that the various foos are being written to it? The second version involves more typing. But it tells you exactly what it's doing. Surely it is better. Regards, Phil.

On 10/6/07, Phil Endecott <spam_from_boost_dev@chezphil.org> wrote:
I haven't been following this thread, but my radar spotted this:
Now operator<<() is used instead of c'tors, this has three advantages:
Hmmm, someone else is tempted to invent yet another use for operator<< ?
If we keep doing this, we'll end up with entire functions where everything is done using << and there are no alphabetic identifiers at all! In this case, compare
f << &foo2 << foo4 << foo3 << &foo1 << foo5;
with
f.add_overload(&foo2); f.add_overload(foo4); f.add_overload(foo3); f.add_overload(&foo1); f.add_overload(foo5);
The first version involves less typing. But, to someone who did not write the code, wouldn't it be reasonable to look at it and think that f is a file and that the various foos are being written to it?
The second version involves more typing. But it tells you exactly what it's doing. Surely it is better.
The important update of this version of overload.hpp is that indices are avoided and the order of registering the overload functions can be random, i.e. has not to follow the order of declaration of the signatures that the overload class supports. Choosing add_overload(), operator<<() or something else is just a taste matter IMHO. Using operator<<() would be nice, but if this can create confusion it can be changed to something else 'Surely better'. Marco

Marco Costalba wrote:
The important update of this version of overload.hpp is that indices are avoided and the order of registering the overload functions can be random, i.e. has not to follow the order of declaration of the signatures that the overload class supports.
There's a big problem with that: you can't (there's no way) to deduce the signatures of polymorphic function objects. Example: struct square { template <typename T> T operator()(T x) const; };
Choosing add_overload(), operator<<() or something else is just a taste matter IMHO.
Using operator<<() would be nice, but if this can create confusion it can be changed to something else 'Surely better'.
I don't quite like the operator in this case, FWIW. As Dave (A) always says, use of such operators should be idiomatic. In this case, it is not. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

On 10/7/07, Joel de Guzman <joel@boost-consulting.com> wrote:
Using operator<<() would be nice, but if this can create confusion it can be changed to something else 'Surely better'.
I don't quite like the operator in this case, FWIW. As Dave (A) always says, use of such operators should be idiomatic. In this case, it is not.
Ok, I have removed operator<<(), now test example is: int main() { typedef boost::tuple< int(char) , double(int, char) , char(std::string) , void(std::string, std::string, std::string) , int() > Signatures; boost::overload<Signatures> f; // assign functions in any order f.add_overload(foo4); f.add_overload(foo2); f.add_overload(foo1); f.add_overload(foo5); f.add_overload(foo3); int i = f('x'); double d = f(123, 'x'); char c = f("hello"); int k = f(); f("Hello", ", World", ", I'm Joel"); BOOST_ASSERT(i == 123); BOOST_ASSERT(d > 123.455 && d < 123.457); BOOST_ASSERT(c == 'x'); BOOST_ASSERT(k == 7); return boost::report_errors(); } BTW I have also changed the mechanism to assign the functions, instead of operator=() overloads now I use a metafunction to find the type, see http://digilander.libero.it/mcostalba/boost_overload/overload.hpp I don't have fixed the problem spotted by Joel, in that it still fails if a functor instead of a function pointer is passed to add_overload(), but I would think this new tecnique could be more extensible the the former. In particular the core type matching is now: boost::is_same<F, T>::value where F is the type of the function pointer to store and T is the type of the n-th element of the 'Signatures' tuple. I would think to fix completely the problem reported by Joel we could write instead: boost::is_convertible<F, boost::function<T> > But for unknown reasons this fails! All types of function pointers match! Could someone please be so kind to enlight me? Thanks Marco

On Sun, 07 Oct 2007 10:41:52 +0200, Marco Costalba <mcostalba@gmail.com> wrote:
I would think to fix completely the problem reported by Joel we could write instead:
boost::is_convertible<F, boost::function<T> >
But for unknown reasons this fails! All types of function pointers match!
Could someone please be so kind to enlight me?
Thanks Marco
Because boost::function has a constructor whose behavior is like this: template< typename Functor > function (Functor const& f) it skips only integral type through enable_if. So, except integral, everything is convertible to boost::function even apples. In order to implement signature deduction I exploits a support utility used in the implementation of boost::function and a lot of metaprogramming. Give a glance to detail::function::get_function_tag in function_base.hpp, in order to learn how to discern between different kind of functors. Regard, Marco Cecchetti -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

Marco wrote:
On Sun, 07 Oct 2007 10:41:52 +0200, Marco Costalba <mcostalba@gmail.com> wrote:
I would think to fix completely the problem reported by Joel we could write instead:
boost::is_convertible<F, boost::function<T> >
But for unknown reasons this fails! All types of function pointers match!
Could someone please be so kind to enlight me?
Thanks Marco
Because boost::function has a constructor whose behavior is like this:
template< typename Functor > function (Functor const& f)
it skips only integral type through enable_if.
So, except integral, everything is convertible to boost::function even apples.
In order to implement signature deduction I exploits a support utility used in the implementation of boost::function and a lot of metaprogramming. Give a glance to detail::function::get_function_tag in function_base.hpp, in order to learn how to discern between different kind of functors.
Tobias (Schwinger) has this excellent library for dealing with function detection: Boost.function_types. It's in SVN now... However, I do not think this will help at all. Ok, so, say we have a polymorphic function (object) called pf. Then we have an overload set with 5 signatures, ov. pf can deal with 3 of them (say the first three). Now, how do you automatically "assign" pf to the first three overloads? You can't. There's no way to detect the signature of a template function (the operator()): Here's what I mean. Using the "add" syntax: ov.add(pf); // which one? duh! Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

On 10/8/07, Joel de Guzman <joel@boost-consulting.com> wrote:
There's no way to detect the signature of a template function (the operator()):
Perhaps you don't need this. You only need to check if the template function operator() matches one signature in the Signatures set. I have found this nice (and very small) code from Paul Mensonides that seems to works (at least for me) http://www.mail-archive.com/boost@lists.boost.org/msg00164.html The limitation is that you have to specify the type of the function, but in our case is not a problem because we have a finite set called 'Signatures' among which to choose the operator() type. As you can see from his testing example: truct X { void operator()(void) { return; } }; struct Y { }; struct Z { template<class T> T operator()(T v) const { return v; } }; int main(void) { std::cout << has_function_call<void (X::*)(void)>::value << '\n' << has_function_call<void (Y::*)(void)>::value << '\n' << has_function_call<int (Z::*)(int) const>::value << '\n'; return 0; } It is possible to check against any operator() given that you now the signatures you are looking for. Now the challange is, given a function obect of class F, to forge a way to loop across Signatures, that are function signatures, void (void) void (void) int (int) const transform in the corresponding member signatures of class F void (F::*)(void) void (F::*)(void) int (F::*)(int) const And check each one with has_function_call() until a match is found or return an error otherwise. Easier to say then to do ;-) Marco

Marco Costalba wrote:
On 10/8/07, Joel de Guzman <joel@boost-consulting.com> wrote:
There's no way to detect the signature of a template function (the operator()):
Perhaps you don't need this. You only need to check if the template function operator() matches one signature in the Signatures set.
I have found this nice (and very small) code from Paul Mensonides that seems to works (at least for me)
http://www.mail-archive.com/boost@lists.boost.org/msg00164.html
The limitation is that you have to specify the type of the function, but in our case is not a problem because we have a finite set called 'Signatures' among which to choose the operator() type.
As you can see from his testing example:
[snip code]
And check each one with has_function_call() until a match is found or return an error otherwise.
Easier to say then to do ;-)
Cool! So if the RHS is a polymorphic function then it can be assigned to all of the compatible Boost.Function objects? Nice! Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

On Mon, 08 Oct 2007 07:39:22 +0200, Marco Costalba <mcostalba@gmail.com> wrote:
On 10/8/07, Joel de Guzman <joel@boost-consulting.com> wrote:
There's no way to detect the signature of a template function (the operator()):
Perhaps you don't need this. You only need to check if the template function operator() matches one signature in the Signatures set.
I have found this nice (and very small) code from Paul Mensonides that seems to works (at least for me)
http://www.mail-archive.com/boost@lists.boost.org/msg00164.html
The limitation is that you have to specify the type of the function, but in our case is not a problem because we have a finite set called 'Signatures' among which to choose the operator() type.
As you can see from his testing example:
truct X { void operator()(void) { return; } };
struct Y { };
struct Z { template<class T> T operator()(T v) const { return v; } };
int main(void) { std::cout << has_function_call<void (X::*)(void)>::value << '\n' << has_function_call<void (Y::*)(void)>::value << '\n' << has_function_call<int (Z::*)(int) const>::value << '\n'; return 0; }
It is possible to check against any operator() given that you now the signatures you are looking for. Now the challange is, given a function obect of class F, to forge a way to loop across Signatures, that are function signatures,
void (void) void (void) int (int) const
transform in the corresponding member signatures of class F
void (F::*)(void) void (F::*)(void) int (F::*)(int) const
And check each one with has_function_call() until a match is found or return an error otherwise.
Easier to say then to do ;-)
Marco
This is exactly how my second implementation works. :-) See my proposal: http://archives.free.net.ph/message/20071007.223315.b8f57ef5.en.html Regards, Marco -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

On 10/8/07, Marco Costalba <mcostalba@gmail.com> wrote:
Easier to say then to do ;-)
Ok I have pushed the (final ?) implementation of overload called "slim" overload because it's much more light and less feature packed then Marco Cecchetti's one. In Vault, the file is http://www.boost-consulting.com/vault/index.php?action=downloadfile&filename... On my host files are: http://digilander.libero.it/mcostalba/boost_overload/test.cpp http://digilander.libero.it/mcostalba/boost_overload/overload.hpp http://digilander.libero.it/mcostalba/boost_overload/is_compatible.hpp Marco

Hi, Marco Costalba <mcostalba <at> gmail.com> writes:
Ok I have pushed the (final ?) implementation of overload called "slim" overload because it's much more light and less feature packed then Marco Cecchetti's one.
boost::overload < int(char) , double(int, char) , char(std::string) , void(std::string, std::string, std::string) , int()
f;
// assign functions in any order, as pointers or plain types std::cout << f.set(&foo4) << std::endl; std::cout << f.set(&foo2) << std::endl; std::cout << f.set( foo1) << std::endl; std::cout << f.set( foo5) << std::endl; std::cout << f.set( foo3) << std::endl;
Here's a completely different idea. struct overload_set { int overload(int_<1>, char a) const { return foo1(a); } double overload(int_<2>, int a, char b) const { return foo2(a, b); } char overload(int_<3>, std::string a) const { return foo3(a); } // ... }; This struct can be wrapped into a fusion sequence. Once it's done, transforming it into a tuple of boost::functions is an exercise for a fusion user. Code is here http://cpp-experiment.cvs.sourceforge.net/cpp-experiment/overloads/ I don't remember if the last version can be compiled at all but I remember I couldn't compile in on VC 7.1 (not sure about 8.0). -- Alexander

"Marco Costalba" <mcostalba@gmail.com> writes:
boost::overload<Signatures> f;
// assign functions in any order f.add_overload(foo4);
Given that the entire point is to hold overloads, isn't "add_overload" a bit redundant? Why not just "add"? -Miles -- .Numeric stability is probably not all that important when you're guessing.

On 10/7/07, Miles Bader <miles@gnu.org> wrote:
"Marco Costalba" <mcostalba@gmail.com> writes:
boost::overload<Signatures> f;
// assign functions in any order f.add_overload(foo4);
Given that the entire point is to hold overloads, isn't "add_overload" a bit redundant? Why not just "add"?
Yes I agree, also because 'overload' is already the name of the struct so perhaps add_function() would be better but also functors can be added so....perhaps just add() is the best, util now ;-) Marco

Marco Costalba wrote:
On 10/7/07, Miles Bader <miles@gnu.org> wrote:
"Marco Costalba" <mcostalba@gmail.com> writes:
boost::overload<Signatures> f;
// assign functions in any order f.add_overload(foo4);
Given that the entire point is to hold overloads, isn't "add_overload" a bit redundant? Why not just "add"?
Yes I agree, also because 'overload' is already the name of the struct so perhaps add_function() would be better but also functors can be added so....perhaps just add() is the best, util now ;-)
"add" looks good, until you "add" something outside the overload set. You can't. The right word is "assign". But then what's wrong with operator=? f = &foo4; f = &foo2; f = &foo1; f = &foo5; f = &foo3; It has the right semantics and is very idiomatic. This is how Boost.Function does it. Only in this case, we can have many mappings instead of just one. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

On 10/8/07, Joel de Guzman <joel@boost-consulting.com> wrote:
Marco Costalba wrote:
On 10/7/07, Miles Bader <miles@gnu.org> wrote:
"Marco Costalba" <mcostalba@gmail.com> writes:
boost::overload<Signatures> f;
// assign functions in any order f.add_overload(foo4);
Given that the entire point is to hold overloads, isn't "add_overload" a bit redundant? Why not just "add"?
Yes I agree, also because 'overload' is already the name of the struct so perhaps add_function() would be better but also functors can be added so....perhaps just add() is the best, util now ;-)
"add" looks good, until you "add" something outside the overload set. You can't. The right word is "assign". But then what's wrong with operator=?
f = &foo4; f = &foo2; f = &foo1; f = &foo5; f = &foo3;
It has the right semantics and is very idiomatic. This is how Boost.Function does it. Only in this case, we can have many mappings instead of just one.
I would prefer 'add' or 'assign' here because 'overload' is a kind of a container while fooX are single functions. My intuitive idea of operator=() is that at the end what is at the left is == of what is at the right, in other words: std::string a; a = "apple"; // now I would think 'a' is an apple a = "blueberry"; // now 'a' is *no more* an apple, is a blueberry assert(a=="apple"); // ??? strange last assignement was a bluebarry here! So, because foo1 != foo2 !=...foox I would find more appropiate 'add', 'assign', 'register', 'push' more then 'set', or '=' IOW I see operator=() more naturally used between a variable and a value or another variable of the same type, not to add elements to, say, a vector. std::vector<int> v; v = 3; v = 10; v = 7; Strange! Marco

Marco Costalba wrote:
It has the right semantics and is very idiomatic. This is how Boost.Function does it. Only in this case, we can have many mappings instead of just one.
I would prefer 'add' or 'assign' here because 'overload' is a kind of a container while fooX are single functions.
My intuitive idea of operator=() is that at the end what is at the left is == of what is at the right, in other words:
std::string a; a = "apple"; // now I would think 'a' is an apple a = "blueberry"; // now 'a' is *no more* an apple, is a blueberry
assert(a=="apple"); // ??? strange last assignement was a bluebarry here!
Assignment can be lossy, you know. Here's a sample: int x; x = 0.0001; x == 0.0001; // ??? huh That "overloads" is a container is an implementation detail. Or how about: std::string a; a = 'x'; a == 'x'; // oops can't compare char and string at any rate, It *is* possible to follow the semantics of Boost.Function: http://boost.org/doc/html/function/tutorial.html#id1187293 int compute_with_X(X*, int); f = &X::foo; assert(f == &X::foo); assert(&compute_with_X != f); by using Boost Function itself to do the comparison. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

On 10/8/07, Joel de Guzman <joel@boost-consulting.com> wrote:
Marco Costalba wrote:
It has the right semantics and is very idiomatic. This is how Boost.Function does it. Only in this case, we can have many mappings instead of just one.
I would prefer 'add' or 'assign' here because 'overload' is a kind of a container while fooX are single functions.
My intuitive idea of operator=() is that at the end what is at the left is == of what is at the right, in other words:
std::string a; a = "apple"; // now I would think 'a' is an apple a = "blueberry"; // now 'a' is *no more* an apple, is a blueberry
assert(a=="apple"); // ??? strange last assignement was a bluebarry here!
Assignment can be lossy, you know. Here's a sample:
int x; x = 0.0001; x == 0.0001; // ??? huh
That "overloads" is a container is an implementation detail. Or how about:
std::string a; a = 'x'; a == 'x'; // oops can't compare char and string
at any rate, It *is* possible to follow the semantics of Boost.Function: http://boost.org/doc/html/function/tutorial.html#id1187293
I've tried to understand why it seems strange to me the proposed operator=() for assigning functions to overload: void foo1(); int foo2(int); overload f; f = &foo1; f = &foo2; I came to the conclusion that all boils down to transitive property of equality. In other words until childhood we are teached that If a == b and b == c, then a == c Because the following line if (a = b) // here = instead of == is intended assert(a==b); should never fail for any properly defined operator=() and operator==() it derives that operator=() as proposed for our overload does not satisfy the above very intuitive concepts (because &foo1 != &foo2) so I would say it cannot be called 'idiomatic' for this case. Marco

Marco Costalba wrote:
On 10/8/07, Joel de Guzman <joel@boost-consulting.com> wrote:
Marco Costalba wrote:
It has the right semantics and is very idiomatic. This is how Boost.Function does it. Only in this case, we can have many mappings instead of just one.
I would prefer 'add' or 'assign' here because 'overload' is a kind of a container while fooX are single functions.
My intuitive idea of operator=() is that at the end what is at the left is == of what is at the right, in other words:
std::string a; a = "apple"; // now I would think 'a' is an apple a = "blueberry"; // now 'a' is *no more* an apple, is a blueberry
assert(a=="apple"); // ??? strange last assignement was a bluebarry here! Assignment can be lossy, you know. Here's a sample:
int x; x = 0.0001; x == 0.0001; // ??? huh
That "overloads" is a container is an implementation detail. Or how about:
std::string a; a = 'x'; a == 'x'; // oops can't compare char and string
at any rate, It *is* possible to follow the semantics of Boost.Function: http://boost.org/doc/html/function/tutorial.html#id1187293
I've tried to understand why it seems strange to me the proposed operator=() for assigning functions to overload:
void foo1(); int foo2(int);
overload f; f = &foo1; f = &foo2;
I came to the conclusion that all boils down to transitive property of equality. In other words until childhood we are teached that
If a == b and b == c, then a == c
Because the following line
if (a = b) // here = instead of == is intended assert(a==b);
should never fail for any properly defined operator=() and operator==() it derives that operator=() as proposed for our overload does not satisfy the above very intuitive concepts (because &foo1 != &foo2) so I would say it cannot be called 'idiomatic' for this case.
Yep. Agreed. See my other post why I am convinced your intuition is correct :-) No need to convince me more ;) Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

On 10/8/07, Joel de Guzman <joel@boost-consulting.com> wrote:
Marco Costalba wrote:
Because the following line
if (a = b) // here = instead of == is intended assert(a==b);
should never fail for any properly defined operator=() and operator==() it derives that operator=() as proposed for our overload does not satisfy the above very intuitive concepts (because &foo1 != &foo2) so I would say it cannot be called 'idiomatic' for this case.
Yep. Agreed. See my other post why I am convinced your intuition is correct :-) No need to convince me more ;)
How about 'register' instead of 'add' or 'assign' ? overloads<void(int), void(std::string)> functions; functions.register(&foo1); functions.register(&foo2); ? This way we can also have something like: functions << register(&foo1) << register(&foo2); ? The above suggestion follows the notion of directives, which are being passed to an object to invoke some sort of behavior. This might be similar to something like: std::cout << std::endl; -- Dean Michael C. Berris Software Engineer, Friendster, Inc. [http://cplusplus-soup.blogspot.com/] [mikhailberis@gmail.com] [+63 928 7291459] [+1 408 4049523]

On 10/9/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
On 10/8/07, Joel de Guzman <joel@boost-consulting.com> wrote:
Marco Costalba wrote:
Because the following line
if (a = b) // here = instead of == is intended assert(a==b);
should never fail for any properly defined operator=() and operator==() it derives that operator=() as proposed for our overload does not satisfy the above very intuitive concepts (because &foo1 != &foo2) so I would say it cannot be called 'idiomatic' for this case.
Yep. Agreed. See my other post why I am convinced your intuition is correct :-) No need to convince me more ;)
How about 'register' instead of 'add' or 'assign' ?
Does is "register" a reserved keyword? Marco

On Tue, 09 Oct 2007 12:54:11 +0200, Marco Costalba <mcostalba@gmail.com> wrote:
On 10/9/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
On 10/8/07, Joel de Guzman <joel@boost-consulting.com> wrote:
Marco Costalba wrote:
Because the following line
if (a = b) // here = instead of == is intended assert(a==b);
should never fail for any properly defined operator=() and operator==() it derives that operator=() as proposed for our
overload
does not satisfy the above very intuitive concepts (because &foo1 != &foo2) so I would say it cannot be called 'idiomatic' for this case.
Yep. Agreed. See my other post why I am convinced your intuition is correct :-) No need to convince me more ;)
How about 'register' instead of 'add' or 'assign' ?
Does is "register" a reserved keyword?
Marco
Yes it's a storage specifier. Marco Cecchetti -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

On 10/9/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 10/9/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
How about 'register' instead of 'add' or 'assign' ?
Does is "register" a reserved keyword?
Oh, yeah. Stupid me. .register_() or .map() would say it better than .assign() or .add(). Let me make a case against 'add()'. overload<...> functions; functions.add(&foo1); functions.add(&foo2); That would imply that 'functions' would contain both foo1 and foo2 -- but if foo1 and foo2 have the same signature, then functions would not contain both. 'add' does not convey the correct idiom, rather it misleads the reader. OTOH, register_() or map() would say that you're registering a function or mapping a function to an appropriate signature or signatures in the overloaded function wrapper: overload<...> functions; functions.map(&foo1); functions.map(&foo2); ... functions.register_(&foo1); functions.register_(&foo2); "register_" has many more letters than "map" though they both (at least I think) convey the intentions better than add() or assign(). Then that way we can also do this: functions << map(&foo1) << map(&foo2) ; functions << register_(&foo1) << register_(&foo2); HTH -- Dean Michael C. Berris Software Engineer, Friendster, Inc. [http://cplusplus-soup.blogspot.com/] [mikhailberis@gmail.com] [+63 928 7291459] [+1 408 4049523]

Dean Michael Berris wrote:
On 10/9/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 10/9/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
How about 'register' instead of 'add' or 'assign' ?
Does is "register" a reserved keyword?
Oh, yeah. Stupid me.
.register_() or .map() would say it better than .assign() or .add(). Let me make a case against 'add()'.
Hey, nuff of the bike shed ;-) Any will do :P There's bigger fish to fry... like... docs! Ahem ahem ahem :P Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

On 10/9/07, Joel de Guzman <joel@boost-consulting.com> wrote:
Dean Michael Berris wrote:
On 10/9/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 10/9/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
How about 'register' instead of 'add' or 'assign' ?
Does is "register" a reserved keyword?
Oh, yeah. Stupid me.
.register_() or .map() would say it better than .assign() or .add(). Let me make a case against 'add()'.
Hey, nuff of the bike shed ;-) Any will do :P There's bigger fish to fry... like... docs! Ahem ahem ahem :P
Okay. :D So where is it located currently and how to we do this? Would a google document in the meantime help? Perhaps if either Marco's would upload their implementations somewhere so that others can start writing documentation for it? Should we merge both efforts and put it in the vault? Or would this kind of thing be welcome in the Boost SVN sandbox? -- Dean Michael C. Berris Software Engineer, Friendster, Inc. [http://cplusplus-soup.blogspot.com/] [mikhailberis@gmail.com] [+63 928 7291459] [+1 408 4049523]

On 10/9/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
Okay. :D
So where is it located currently and how to we do this? Would a google document in the meantime help? Perhaps if either Marco's would upload their implementations somewhere so that others can start writing documentation for it?
I have already uploaded latest version in http://digilander.libero.it/mcostalba/boost_overload/overload.hpp http://digilander.libero.it/mcostalba/boost_overload/test.hpp BTW regarding API to overload we could mimic STL, in particular std::map::insert() says: "The insert member function returns a pair whose bool component returns true if an insertion was made and false if the map already contained an element whose key had an equivalent value in the ordering" Or this sounds too overkilling ?

On 10/9/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 10/9/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
Okay. :D
So where is it located currently and how to we do this? Would a google document in the meantime help? Perhaps if either Marco's would upload their implementations somewhere so that others can start writing documentation for it?
I have already uploaded latest version in
http://digilander.libero.it/mcostalba/boost_overload/overload.hpp http://digilander.libero.it/mcostalba/boost_overload/test.hpp
Sweet, let me take a look and start writing documentation. I'll share a Google document with those interested so that we can get something started quickly.
BTW regarding API to overload we could mimic STL, in particular std::map::insert() says:
"The insert member function returns a pair whose bool component returns true if an insertion was made and false if the map already contained an element whose key had an equivalent value in the ordering"
Interesting. Though I'm not sure about insert -- but if we make it work this way, we're going to have to consider the case where a function gets mapped to multiple signatures.
Or this sounds too overkilling ?
This I think is too much. But I might be wrong. :D -- Dean Michael C. Berris Software Engineer, Friendster, Inc. [http://cplusplus-soup.blogspot.com/] [mikhailberis@gmail.com] [+63 928 7291459] [+1 408 4049523]

On Tue, 09 Oct 2007 13:48:26 +0200, Dean Michael Berris <mikhailberis@gmail.com> wrote:
Hey, nuff of the bike shed ;-) Any will do :P There's bigger fish to fry... like... docs! Ahem ahem ahem :P
Okay. :D
So where is it located currently and how to we do this? Would a google document in the meantime help? Perhaps if either Marco's would upload their implementations somewhere so that others can start writing documentation for it?
Should we merge both efforts and put it in the vault? Or would this kind of thing be welcome in the Boost SVN sandbox?
I'm sorry I haven't a place where to upload my implementation, but I've attached it to my previous proposal post: http://lists.boost.org/Archives/boost/2007/10/128289.php and this is the link to the attachment: http://lists.boost.org/Archives/boost/att-128289/overload.zip About method name, at present I keep my generic "set" at least is simmetric with "get" :-) Obviously I'm open to discussions, but don't make it the main issue of the project :-) Regards, Marco Cecchetti -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

Hi Marco! On 10/9/07, Marco <mrcekets@gmail.com> wrote:
On Tue, 09 Oct 2007 13:48:26 +0200, Dean Michael Berris <mikhailberis@gmail.com> wrote:
Hey, nuff of the bike shed ;-) Any will do :P There's bigger fish to fry... like... docs! Ahem ahem ahem :P
Okay. :D
So where is it located currently and how to we do this? Would a google document in the meantime help? Perhaps if either Marco's would upload their implementations somewhere so that others can start writing documentation for it?
Should we merge both efforts and put it in the vault? Or would this kind of thing be welcome in the Boost SVN sandbox?
I'm sorry I haven't a place where to upload my implementation, but I've attached it to my previous proposal post:
http://lists.boost.org/Archives/boost/2007/10/128289.php
and this is the link to the attachment:
http://lists.boost.org/Archives/boost/att-128289/overload.zip
It's alright, thanks. :)
About method name, at present I keep my generic "set" at least is simmetric with "get" :-) Obviously I'm open to discussions, but don't make it the main issue of the project :-)
I agree. 'set' seems alright to me too. It's add and insert that I have problems with. :) I'm sharing the Google document with you, Joel De Guzman, and Marco Costalba. I like the implementation you've come up with using just Boost.PP instead of relying on Boost.Tuple -- this makes it easier to pre-process and output as a preprocessed header, perfect for easy trasport in different situations when only Boost.Function and not Boost.PP is available. I'm writing the introductory documentation, and I'd love to help out with filling out the design and concepts area of the document. Please let me know if anybody else wants a link to the document so that I can share it with you as well.
Regards, Marco Cecchetti
Thanks again! -- Dean Michael C. Berris Software Engineer, Friendster, Inc. [http://cplusplus-soup.blogspot.com/] [mikhailberis@gmail.com] [+63 928 7291459] [+1 408 4049523]

Dean Michael Berris wrote:
On 10/9/07, Marco <mrcekets@gmail.com> wrote:
About method name, at present I keep my generic "set" at least is simmetric with "get" :-) Obviously I'm open to discussions, but don't make it the main issue of the project :-)
I agree. 'set' seems alright to me too. It's add and insert that I have problems with. :)
How about "enable" inspired by controlling overload resolution with enable_if. Thanks, Michael Marcin

On 10/9/07, Michael Marcin <mmarcin@method-solutions.com> wrote:
Dean Michael Berris wrote:
On 10/9/07, Marco <mrcekets@gmail.com> wrote:
About method name, at present I keep my generic "set" at least is simmetric with "get" :-) Obviously I'm open to discussions, but don't make it the main issue of the project :-)
I agree. 'set' seems alright to me too. It's add and insert that I have problems with. :)
How about "enable" inspired by controlling overload resolution with enable_if.
At the risk of bring down Joel's wrath, I'll add another suggestion to the hat. What about 'include'? As in, "include this in the overload resolution set." --Michael Fawcett

On 10/10/07, Michael Fawcett <michael.fawcett@gmail.com> wrote:
On 10/9/07, Michael Marcin <mmarcin@method-solutions.com> wrote:
Dean Michael Berris wrote:
On 10/9/07, Marco <mrcekets@gmail.com> wrote:
About method name, at present I keep my generic "set" at least is simmetric with "get" :-) Obviously I'm open to discussions, but don't make it the main issue of the project :-)
I agree. 'set' seems alright to me too. It's add and insert that I have problems with. :)
How about "enable" inspired by controlling overload resolution with enable_if.
At the risk of bring down Joel's wrath, I'll add another suggestion to the hat.
I'm risking Joel's wrath as well here by obliging the discussion, but then I'll go ahead and share my thoughts nonetheless. :)
What about 'include'? As in, "include this in the overload resolution set."
I thought about this, and the only problem is that it assumes that 'include' does not replace the already existing mapping between a function signature and the actual function being 'included'. Consider: void foo(int) { }; void bar(int) { }; overloads<void(int), void(std::string)> functions; functions.include(&foo); functions.include(&bar); functions(1); // will imply that 'foo' and 'bar' will both be called The above code suggests that functions(1) should call both foo and bar, because both functions are included in the overload set. If this is the behavior you're looking for, I think Boost.Signals does tihs perfectly well -- only Boost.Signals is also monomorphic, meaning it contains (like Boost.Function) only function wrappers that share a single signature. Thinking about it more, maybe Boost.Signals might also benefit from something like Boost.Overloads because if for example slots (or handlers) can be connected to signals and dispatched depending on the signature of the signal invoked, then we have a clean way of providing a coherent interface that's statically dispatched *and* idiomatically sound. The drawback is I think this might change the way Boost.Signals is implemented -- currently there's an external library built, which I'm not sure will be affected with the use of Boost.Overloads. Besides, applying it to the concept of Signals might be pushing it -- but I may be wrong. Nonetheless, I'm thinking at this time 'set' is fine, especially when it supports both argument type deduction *and* the explicit index specification. Interesting idea though, thanks for sharing your thoughts. :) -- Dean Michael C. Berris Software Engineer, Friendster, Inc. [http://cplusplus-soup.blogspot.com/] [mikhailberis@gmail.com] [+63 928 7291459] [+1 408 4049523]

On 10/9/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
I thought about this, and the only problem is that it assumes that 'include' does not replace the already existing mapping between a function signature and the actual function being 'included'. Consider:
void foo(int) { }; void bar(int) { };
overloads<void(int), void(std::string)> functions;
functions.include(&foo); functions.include(&bar); functions(1); // will imply that 'foo' and 'bar' will both be called
The above code suggests that functions(1) should call both foo and bar, because both functions are included in the overload set.
It doesn't suggest that to me. If we were talking normal overload sets, it would fail to compile because it was ambiguous. The user is trying to introduce an ambiguity with the second include line, and he's ignoring the return value, which I presume contains 'false', as in, not inserted. --Michael Fawcett

Michael Fawcett wrote:
On 10/9/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
I thought about this, and the only problem is that it assumes that 'include' does not replace the already existing mapping between a function signature and the actual function being 'included'. Consider:
void foo(int) { }; void bar(int) { };
overloads<void(int), void(std::string)> functions;
functions.include(&foo); functions.include(&bar); functions(1); // will imply that 'foo' and 'bar' will both be called
The above code suggests that functions(1) should call both foo and bar, because both functions are included in the overload set.
It doesn't suggest that to me. If we were talking normal overload sets, it would fail to compile because it was ambiguous. The user is trying to introduce an ambiguity with the second include line, and he's ignoring the return value, which I presume contains 'false', as in, not inserted.
I'll persist (yes, yes ... the imfamous bicycle shed): What's wrong with add: functions.add(&foo); functions.add(&foo); // Throws functions.insert(&foo); // Returns false functions.replace(&foo); // Overwrites if exists, inserts if not The above is based on the fact that only one overload of each signature is stored - analogous to method overloads. If some kind of multiple dispatch is desired - how about "multi_overloads" (compare set/multiset, map/multimap). / Johan

On Wed, 10 Oct 2007 08:24:08 +0200, Johan Nilsson <r.johan.nilsson@gmail.com> wrote:
Michael Fawcett wrote:
On 10/9/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
I thought about this, and the only problem is that it assumes that 'include' does not replace the already existing mapping between a function signature and the actual function being 'included'.
[snip]
I'll persist (yes, yes ... the imfamous bicycle shed): What's wrong with add:
functions.add(&foo); functions.add(&foo); // Throws functions.insert(&foo); // Returns false functions.replace(&foo); // Overwrites if exists, inserts if not
The above is based on the fact that only one overload of each signature is stored - analogous to method overloads.
If some kind of multiple dispatch is desired - how about "multi_overloads" (compare set/multiset, map/multimap).
/ Johan
Well, my point of view is that you shouldn't see the proposed implementation as a container but just as an extension of Boost.Function. It would be overkilling if Boost.Function had method like "insert" and "replace" instead of a simple operator= , and, IMO, the same it's true for the proposed overload implementation. Regards, Marco -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

Marco wrote:
On Wed, 10 Oct 2007 08:24:08 +0200, Johan Nilsson <r.johan.nilsson@gmail.com> wrote:
Michael Fawcett wrote:
On 10/9/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
I thought about this, and the only problem is that it assumes that 'include' does not replace the already existing mapping between a function signature and the actual function being 'included'. [snip] I'll persist (yes, yes ... the imfamous bicycle shed): What's wrong with add:
functions.add(&foo); functions.add(&foo); // Throws functions.insert(&foo); // Returns false functions.replace(&foo); // Overwrites if exists, inserts if not
The above is based on the fact that only one overload of each signature is stored - analogous to method overloads.
If some kind of multiple dispatch is desired - how about "multi_overloads" (compare set/multiset, map/multimap).
/ Johan
Well, my point of view is that you shouldn't see the proposed implementation as a container but just as an extension of Boost.Function. It would be overkilling if Boost.Function had method like "insert" and "replace" instead of a simple operator= , and, IMO, the same it's true for the proposed overload implementation.
I agree. Let's keep it simple. Less is more. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Marco wrote:
On Wed, 10 Oct 2007 08:24:08 +0200, Johan Nilsson <r.johan.nilsson@gmail.com> wrote:
Michael Fawcett wrote:
On 10/9/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
I thought about this, and the only problem is that it assumes that 'include' does not replace the already existing mapping between a function signature and the actual function being 'included'.
[snip]
I'll persist (yes, yes ... the imfamous bicycle shed): What's wrong with add:
functions.add(&foo); functions.add(&foo); // Throws functions.insert(&foo); // Returns false functions.replace(&foo); // Overwrites if exists, inserts if not
The above is based on the fact that only one overload of each signature is stored - analogous to method overloads.
If some kind of multiple dispatch is desired - how about "multi_overloads" (compare set/multiset, map/multimap).
/ Johan
Well, my point of view is that you shouldn't see the proposed implementation as a container but just as an extension of Boost.Function. It would be overkilling if Boost.Function had method like "insert" and "replace" instead of a simple operator= , and, IMO, the same it's true for the proposed overload implementation.
Sorry. I still believe that this violates the LSP. IMHO "overloads" should be designed for standalone usage, with method naming (and perhaps operator overloading) that reflect their true nature. If you want to be able to use "overloads" just as an extension of Boost.Function, supply the users with e.g. an "overloads_function_adapter" wrapper. Nevertheless, I rest my case. My opinion seems to be in minority here. / Johan

On Tue, 09 Oct 2007 19:15:27 +0200, Michael Fawcett <michael.fawcett@gmail.com> wrote:
On 10/9/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
I thought about this, and the only problem is that it assumes that 'include' does not replace the already existing mapping between a function signature and the actual function being 'included'. Consider:
void foo(int) { }; void bar(int) { };
overloads<void(int), void(std::string)> functions;
functions.include(&foo); functions.include(&bar); functions(1); // will imply that 'foo' and 'bar' will both be called
The above code suggests that functions(1) should call both foo and bar, because both functions are included in the overload set.
It doesn't suggest that to me. If we were talking normal overload sets, it would fail to compile because it was ambiguous. The user is trying to introduce an ambiguity with the second include line, and he's ignoring the return value, which I presume contains 'false', as in, not inserted.
--Michael Fawcett _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Not sure, but maybe we're speaking of different "overloads". The overload implementation that I, Marco Costalba and Dean Michael Berris are working on is a multi-signature wrapper of boost.function. The assignment of a functor target mimic the behavior of boost.function: deduced the matching signature the new functor is assigned and the old one, if present, is discarded. At invocation time the implementation relies directly on standard C++ overloading, and mimic its behaviour. Regard, Marco -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

On 10/11/07, Marco <mrcekets@gmail.com> wrote:
On Tue, 09 Oct 2007 19:15:27 +0200, Michael Fawcett <michael.fawcett@gmail.com> wrote:
On 10/9/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
I thought about this, and the only problem is that it assumes that 'include' does not replace the already existing mapping between a function signature and the actual function being 'included'. Consider:
void foo(int) { }; void bar(int) { };
overloads<void(int), void(std::string)> functions;
functions.include(&foo); functions.include(&bar); functions(1); // will imply that 'foo' and 'bar' will both be called
The above code suggests that functions(1) should call both foo and bar, because both functions are included in the overload set.
It doesn't suggest that to me. If we were talking normal overload sets, it would fail to compile because it was ambiguous. The user is trying to introduce an ambiguity with the second include line, and he's ignoring the return value, which I presume contains 'false', as in, not inserted.
Not sure, but maybe we're speaking of different "overloads". The overload implementation that I, Marco Costalba and Dean Michael Berris are working on is a multi-signature wrapper of boost.function. The assignment of a functor target mimic the behavior of boost.function: deduced the matching signature the new functor is assigned and the old one, if present, is discarded. At invocation time the implementation relies directly on standard C++ overloading, and mimic its behaviour.
Yes, I understand that. I was talking about the same thing, only making an analogy to classic overloading. One would not expect the following to compile: void foo(unsigned char c) { } void foo(signed char c) { } foo(1); Just like one shouldn't expect the following to run without error: void foo(int) { }; void bar(int) { }; overloads<void(int), void(std::string)> functions; functions.include(&foo); functions.include(&bar); // return value signifies that ambiguity was resolved by the overloads class, but user ignored it functions(1); In both cases you are introducing an ambiguity. In one case the compiler refuses it, in the other, your overloads class enforces it. I chose 'include' because people often talk in terms of "being included or excluded from the overload resolution set", so 'include' felt right. Hope my reasoning is clearer now, --Michael Fawcett

On Thu, 11 Oct 2007 17:30:42 +0200, Michael Fawcett <michael.fawcett@gmail.com> wrote:
On 10/11/07, Marco <mrcekets@gmail.com> wrote:
On Tue, 09 Oct 2007 19:15:27 +0200, Michael Fawcett <michael.fawcett@gmail.com> wrote:
On 10/9/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
I thought about this, and the only problem is that it assumes that 'include' does not replace the already existing mapping between a function signature and the actual function being 'included'.
Consider:
void foo(int) { }; void bar(int) { };
overloads<void(int), void(std::string)> functions;
functions.include(&foo); functions.include(&bar); functions(1); // will imply that 'foo' and 'bar' will both be called
The above code suggests that functions(1) should call both foo and bar, because both functions are included in the overload set.
It doesn't suggest that to me. If we were talking normal overload sets, it would fail to compile because it was ambiguous. The user is trying to introduce an ambiguity with the second include line, and he's ignoring the return value, which I presume contains 'false', as in, not inserted.
Not sure, but maybe we're speaking of different "overloads". The overload implementation that I, Marco Costalba and Dean Michael Berris are working on is a multi-signature wrapper of boost.function. The assignment of a functor target mimic the behavior of boost.function: deduced the matching signature the new functor is assigned and the old one, if present, is discarded. At invocation time the implementation relies directly on standard C++ overloading, and mimic its behaviour.
Yes, I understand that. I was talking about the same thing, only making an analogy to classic overloading. One would not expect the following to compile:
void foo(unsigned char c) { } void foo(signed char c) { }
foo(1);
Just like one shouldn't expect the following to run without error:
void foo(int) { }; void bar(int) { };
overloads<void(int), void(std::string)> functions;
functions.include(&foo); functions.include(&bar); // return value signifies that ambiguity was resolved by the overloads class, but user ignored it functions(1);
In both cases you are introducing an ambiguity. In one case the compiler refuses it, in the other, your overloads class enforces it.
I chose 'include' because people often talk in terms of "being included or excluded from the overload resolution set", so 'include' felt right.
Hope my reasoning is clearer now,
--Michael Fawcett
I understand your analogy but anyway if we agree that in your example sets/includes "bar" discards "foo" automatically there is no ambiguity that we have to check. Then if you want only to state that this behaviour could be not obvious for the user, I can only say that, IMO, this is more a documentation than an implementation problem. Marco Cecchetti -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

On 10/11/07, Marco <mrcekets@gmail.com> wrote:
I understand your analogy but anyway if we agree that in your example sets/includes "bar" discards "foo" automatically there is no ambiguity that we have to check.
Discarding "foo" *IS* resolving the ambiguity. Discarding is the method overloads implemented to resolve ambiguity, but it doesn't mean that the user wasn't introducing any.
Then if you want only to state that this behaviour could be not obvious for the user, I can only say that, IMO, this is more a documentation than an implementation problem.
Yes, it's a documentation issue. I think you get my analogy. Calling include/set has the potential to overwrite something, just like insert on a std::set has the potential to fail if a duplicate already exists (for that reason alone I would argue against "insert" since it has exactly opposite behavior w.r.t. set/map). If the user chooses to ignore that return value std::pair<bool, iterator> and is surprised by the result, it's his own fault for not reading the documentation and his own fault for not catching the return. We are arguing trivial things. 'include', to me, has the most relevant connotations and precedents, and I'll leave it at that. Wonderful work to all the authors, regardless of what name you choose! :) --Michael Fawcett

I uploaded to boost vault a new version of my implementation of Boost.Overload: http://www.boost-consulting.com/vault/index.php?action=downloadfile&filename... Boost.Overload is a multi-signature overloaded Boost.Function wrapper, which wraps multiple Boost.Function objects of different signatures as a single multi-signature overloaded function wrapper. For a brief introduction you can read some preliminary documentation that was kindly written down by Dean Michael Berris: http://tinyurl.com/3xtbyl For the post of the previous version you should look at: http://lists.boost.org/Archives/boost/2007/10/128289.php What's new: at present I worked on the second implementation only, and what follow is about such implementation; the source code has gone through refactoring and modularization; any dipendency by boost::is_base_of has been removed; the default assignment behaviour for overloaded and polymorfic function objects is changed: now for any signature S, included in an instantiation "o" of the template class overload, that matches at least one of the signatures of the passed function object "f", we have that the object of type boost::function<S> embedded in an instance of type "o" utilizes "f" as its target; example: struct foo { template< typename T > T operator()(T x) { return x + 1; } }; char foo2(std::string ) { return 'x'; } typedef int sig1_t (int ); typedef char sig2_t (std::string ); typedef double sig3_t (double ); int main() { boost::overload<sig1_t,sig2_t,sig3_t> ov; foo f; ov.set(f); // this is equivalent to // ov.set<sig1_t>(f); // ov.set<sig3_t>(f); ov.set(&foo2); // this is equivalent to // ov.set<sig2_t>(&foo2) return 0; } I think that this behaviour is the most natural and the one that is expected by the user. If we want to set a polymorfic function object as the target for only one specific signature we can always rely on set<signature_type>(f) or set<index>(f). I tested the source code with gcc 4.1.2 under Linux. Boost community helpful suggestions and critiques about interface, implementation and documentation are welcome. Above all I'd appreciate anyone pointing out bugs, compatibility issues, and library use cases. Regards, Marco Cecchetti -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

On Tue, 09 Oct 2007 18:22:14 +0200, Michael Marcin <mmarcin@method-solutions.com> wrote:
Dean Michael Berris wrote:
On 10/9/07, Marco <mrcekets@gmail.com> wrote:
About method name, at present I keep my generic "set" at least is simmetric with "get" :-) Obviously I'm open to discussions, but don't make it the main issue of the project :-)
I agree. 'set' seems alright to me too. It's add and insert that I have problems with. :)
How about "enable" inspired by controlling overload resolution with enable_if.
Thanks,
Michael Marcin
IMO, enable doesn't give the idea that we're doing an assignment. So I still prefer "set". However thanks for your interest. Regards, Marco -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

On Tue, 09 Oct 2007 08:41:14 +0200, Marco Costalba <mcostalba@gmail.com> wrote:
I've tried to understand why it seems strange to me the proposed operator=() for assigning functions to overload:
void foo1(); int foo2(int);
overload f; f = &foo1; f = &foo2;
I came to the conclusion that all boils down to transitive property of equality. In other words until childhood we are teached that
If a == b and b == c, then a == c
Because the following line
if (a = b) // here = instead of == is intended assert(a==b);
should never fail for any properly defined operator=() and operator==() it derives that operator=() as proposed for our overload does not satisfy the above very intuitive concepts (because &foo1 != &foo2) so I would say it cannot be called 'idiomatic' for this case.
Marco
I consider operator=() misleading, too. I guess that for &foo1 != &foo2 you mean that their types are not convertible between each other. Marco -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

Marco Costalba wrote:
IOW I see operator=() more naturally used between a variable and a value or another variable of the same type, not to add elements to, say, a vector.
std::vector<int> v; v = 3; v = 10; v = 7;
Strange!
Not so fast: std::string s; s = 'x'; s == 'x'; // ooops can't do Again that "overloads" uses a tuple is an implementation detail. Ok, I don't want to beat this to death. Hmm... ok since we are dealing with an overload set. Perhaps a "set" is a good description of this. So perhaps "add" is not that bad after all (Johan must be smiling :-) ). Or perhaps, the union operator |= might also be a good candidate. I'll leave it up to you guys, your intuitions are fine and cool! :-) Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
Marco Costalba wrote:
[snip]
Yes I agree, also because 'overload' is already the name of the struct so perhaps add_function() would be better but also functors can be added so....perhaps just add() is the best, util now ;-)
"add" looks good, until you "add" something outside the overload set. You can't.
That's why it's good.
The right word is "assign".
I beg to differ.
But then what's wrong with operator=?
f = &foo4; f = &foo2; f = &foo1; f = &foo5; f = &foo3;
At the end of this example one would expect f to only have one overload; foo3. IMHO, "add" is good. If one really needs to use operators for adding overloads, why not use "+="? / Johan

Johan Nilsson wrote:
Joel de Guzman wrote:
Marco Costalba wrote:
[snip]
Yes I agree, also because 'overload' is already the name of the struct so perhaps add_function() would be better but also functors can be added so....perhaps just add() is the best, util now ;-) "add" looks good, until you "add" something outside the overload set. You can't.
That's why it's good.
The right word is "assign".
Why is it good?
I beg to differ.
But then what's wrong with operator=?
f = &foo4; f = &foo2; f = &foo1; f = &foo5; f = &foo3;
At the end of this example one would expect f to only have one overload; foo3.
IMHO, "add" is good. If one really needs to use operators for adding overloads, why not use "+="?
Oh my, getting to be a bicycle shed ;-) Ok, I don't have a strong opinion either way :-) To be honest, I'm not quite sure with all these if they cannot be made to handle polymorphic functions. It kinda defeats the purpose if we need to have a different syntax for polymorphic function objects and function pointers/mem function pointers. So, in the end, an explicit form of "set" is still better, IMO. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

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/

Marco wrote:
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.
Brilliant! Looks good! Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

And finally (sorry for the noise ;-) I would like to write instead of this
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);
Something like ?? type_of ?? f = get_overload(foo1, foo2, foo3, foo4); where 'get_overload' is something along the lines of: template <typename T1, typename T2, typename T3, typename T4> inline overload<tuple<T1, T2, T3, T4> > get_overload(T1 const& f1, T2 const& f2, T3 const& f3, T4 const& f4) { typedef overload<tuple<T1, T2, T3, T4> > F; return F(f1, f2, f3, f4); // well, overload c'tor is still to define ;-) } So to avoid the user to specify the signatures for each function he wants to use. The problem is that I don't know what is the best way to define variable 'f', (type_of ?). There is a way to avoid user to type the signatures, given that he already has the functions (fooX) ? Thanks Marco

Marco Costalba wrote:
On 10/1/07, Joel de Guzman <joel@boost-consulting.com> wrote:
Marco Costalba wrote:
On 10/1/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 10/1/07, Joel de Guzman <joel@boost-consulting.com> 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:
Better. Only relies on tuples. No more. With low level libraries, the ideal is to rely on as little libraries as possible. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Hi Joel! On 9/30/07, Joel de Guzman <joel@boost-consulting.com> wrote:
Joel de Guzman wrote:
I think I've mentioned that I have such a "overloads" library extension in my HD somewhere. At one point, I asked Doug on the possibility of adding it to boost.function and he expressed his interest. Of course that means documentation and stuff. I'll try to see if I can squeeze some time to get this into completion. At any rate, I can post the code sans docs.
[CC'ing Doug]
Ok, here's the proof of concept:
I took a look, and I think this definitely has great potential. :) I'll try my hand at trying to document the concepts, and maybe extending it. I might be wrong though, but it seems that the implementation is limited to 4 overloads to suit the test case. This is understandable, and I think I can try making this more generic (up to 10, just like tuples, or with Boost.PP) and perhaps document the concept for Boost.Function. Thanks for the sample! I definitely think this makes life a bit easier for those who need this functionality. I'll also try my hand at making the assignment operator smarter, and perhaps do away with the set<> member template method. Wish me luck. :D -- Dean Michael C. Berris Software Engineer, Friendster, Inc. [http://cplusplus-soup.blogspot.com/] [mikhailberis@gmail.com] [+63 928 7291459] [+1 408 4049523]

Joel de Guzman <joel <at> boost-consulting.com> writes:
Joel de Guzman wrote: Ok, here's the proof of concept:
I'm very impressed. C++ folks say goodbye to the visitor pattern ;-) BTW, I could do this with dynamic_any: http://tinyurl.com/373wkx (opens ViewVC page for calls.cpp, revision 1.3). -- Alexander

Hmm - what are the benefits/disadvantages of the two implementations - or which should you use? Oliver
Joel de Guzman <joel <at> boost-consulting.com> writes:
Joel de Guzman wrote: Ok, here's the proof of concept:
I'm very impressed. C++ folks say goodbye to the visitor pattern ;-)
BTW, I could do this with dynamic_any: http://tinyurl.com/373wkx (opens ViewVC page for calls.cpp, revision 1.3).
-- Alexander
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

<Oliver.Kowalke <at> qimonda.com> writes:
Hmm - what are the benefits/disadvantages of the two implementations - or which should you use?
[ I'm talking past because I abandoned the library when I was unable to implement multimethods. ] dynamic_any's goal was to mimic values of scripting languages. For example, one could subtract a number from a string containing numeric value and print the result: dynamic_any< /* list of supported operations */ > a("2"), b(1); cout << a - b; Function calls is one particular case of "operation". calls.cpp (http://tinyurl.com/373wkx) defines a list of operations as follow: typedef mpl::list< dynamic_any::function_call<int (int)>, dynamic_any::function_call<double (double)>
ops;
At construction time, a single value functor is created. It must be a functor that can accept one argument of type int or double: dynamic_any<ops> f(_1 + 1); // lambda expression cout << f(136) << '\n'; cout << f(2.1459) << '\n'; This means that any dynamic_any value which supports these operations is callable. You can pass either int or double to such dynamic_any values. Key difference between my interface and Joel's is that Joel sets overloads individually: f.set<0>(&foo1); f.set<1>(&foo2); f.set<2>(&foo3); f.set<3>(&foo4); while I expect a single functor supporting all overloads: _1 + 1; or struct f { int operator(int) const; double operator(double) const; }; -- Alexander

Alexander Nasonov wrote:
Key difference between my interface and Joel's is that Joel sets overloads individually:
f.set<0>(&foo1); f.set<1>(&foo2); f.set<2>(&foo3); f.set<3>(&foo4);
while I expect a single functor supporting all overloads:
_1 + 1;
or
struct f { int operator(int) const; double operator(double) const; };
Yep. Both has its uses. I believe Alexander's code accepts only polymorphic functions. So, you can also use 'overloads' to gather the monomorphic functions and feed that to Alexander's. Cool stuff Alexander! I'd like to use dynamic_any in the lisp/scheme interpreter I'll be writing as an example for spirit2. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman <joel <at> boost-consulting.com> writes:
Yep. Both has its uses. I agree.
I believe Alexander's code accepts only polymorphic functions.
That's right. It's like boost::function except that it can have more than one overload: typedef mpl::list<int (int), double(double)> sigs; multi_function<sigs> f = _1 + 1; f(0); f(0.0);
So, you can also use 'overloads' to gather the monomorphic functions and feed that to Alexander's.
Yes. It would add another level of indirection, though.
Cool stuff Alexander! I'd like to use dynamic_any in the lisp/scheme interpreter I'll be writing as an example for spirit2.
Are you planning to use only function_call operation or all operations? If the latter, I'm not familiar with values in scheme/lisp to say whether dynamic_any fits or not. -- Alexander

Alexander Nasonov wrote:
Cool stuff Alexander! I'd like to use dynamic_any in the lisp/scheme interpreter I'll be writing as an example for spirit2.
Are you planning to use only function_call operation or all operations?
No.
If the latter, I'm not familiar with values in scheme/lisp to say whether dynamic_any fits or not.
I'll know as soon as I get to it :P Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

AMDG Dean Michael Berris <mikhailberis <at> gmail.com> writes:
And since it's linear inheritance, the derived type (or at least the one in the end of the inheritance hierarchy) will inherit all these overloads to operator=() which will enable the compiler to choose at compile time which overload it's going to use depending on what's on the right hand side of the operator=().
As long as you put using base::operator=; in the derived type In Christ, Steven Watanabe

On 10/1/07, Steven Watanabe <steven@providere-consulting.com> wrote:
AMDG
Dean Michael Berris <mikhailberis <at> gmail.com> writes:
And since it's linear inheritance, the derived type (or at least the one in the end of the inheritance hierarchy) will inherit all these overloads to operator=() which will enable the compiler to choose at compile time which overload it's going to use depending on what's on the right hand side of the operator=().
As long as you put using base::operator=; in the derived type
If I recall correctly MSVC 7.1 has problems with chained template inheritance with using base::operator=; directives. It ICEs.
In Christ, Steven Watanabe
-- Felipe Magno de Almeida
participants (14)
-
Alexander Nasonov
-
Dean Michael Berris
-
Felipe Magno de Almeida
-
Joel de Guzman
-
Johan Nilsson
-
Marco
-
Marco Costalba
-
Martin Lutken
-
Michael Fawcett
-
Michael Marcin
-
Miles Bader
-
Oliver.Kowalke@qimonda.com
-
Phil Endecott
-
Steven Watanabe