Macro for using overloaded functions with templated code.

I've written a macro (the implementation is attached) for generating a function object for using overloaded functions with generic code such as the STL algorithms and boost::bind. A simple example of it's use: void foo(int); void foo(char*); GENERATE_OVERLOADED(void, foo); int main() { int values[] = { 1, 2, 3, 4 }; std::for_each(values, values+4, foo_overloaded); } GENERATE_OVERLOADED (yes, the naming is pretty bad) creates an object called which contains overloaded calls to operator() which forward to the named functions. Something like: struct foo_overloaded_type { void operator() const { return foo(); } template <class T1> void operator(T1 const& p1) const { return foo(p1); } template <class T1, class T2> void operator(T1 const& p1, T2 const& p2) const { return foo(p1, p2); } // etc. } foo_overloaded; The main advantage is that you don't have to select the desired overload. It can also be useful when different calls will have different argument types such as iterating over a tuple in fusion (I guess you could call it a visitor). Any comments on this? Would anyone else find this useful? Also, has anyone done something similar? I'd be surprised if no one has, I always feel like I'm missing something when I'm doing this kind of thing. The implementation is lacking in several ways - it doesn't work for non-const references, the return type is fixed, needs to deal with member functions, namespace issues and so on. I suppose, it could also be better integrated with bind, lambda or pheonix. Daniel

On Thu, Nov 18, 2004 at 02:00:40PM +0000, Daniel James wrote:
I've written a macro (the implementation is attached) for generating a function object for using overloaded functions with generic code such as the STL algorithms and boost::bind. A simple example of it's use: [snip] Any comments on this? Would anyone else find this useful? Also, has anyone done something similar? I'd be surprised if no one has, I always feel like I'm missing something when I'm doing this kind of thing.
Out of curiosity my first thought was to see if I could use std::tolower in std::transform, like so: #include "overloaded.hpp" #include <string> #include <algorithm> #include <cctype> using std::tolower; GENERATE_OVERLOADED(int, tolower); int main() { std::string s("FNORD"); std::transform(s.begin(), s.end(), s.begin(), tolower_overloaded); } (The using declaration is needed to prevent the instance of the generated type being named "std::tolower_overloaded") Unfortunately this fails to compile because there is no nullary form of std::tolower so the nullary overload gives this error: /usr/include/ctype.h: In member function `ResultType GENERATE_DETAIL::tolower_overloaded_t<ResultType>::operator()() const': /usr/include/ctype.h:81: error: too few arguments to function `int tolower(int)' tolower.cc:8: error: at this point in file In fact, I get a similar error for the example code in your mail: overloaded.cc: In member function `ResultType GENERATE_DETAIL::foo_overloaded_t<ResultType>::operator()() const': overloaded.cc:7: error: no matching function for call to `foo()' overloaded.cc:4: note: candidates are: void foo(int) overloaded.cc:5: note: void foo(char*) So although I can see uses for this, I can't use it :-) jon -- "The easy confidence with which I know another man's religion is Folly leads me to suspect that my own is also." - Mark Twain

Jonathan Wakely wrote:
In fact, I get a similar error for the example code in your mail:
overloaded.cc: In member function `ResultType GENERATE_DETAIL::foo_overloaded_t<ResultType>::operator()() const': overloaded.cc:7: error: no matching function for call to `foo()' overloaded.cc:4: note: candidates are: void foo(int) overloaded.cc:5: note: void foo(char*)
So although I can see uses for this, I can't use it :-)
Oh dear. I hadn't tested it very thoroughly - it works on g++ versions 2.95 and 3.3, but not 3.4 (which I guess you're using). I'm not sure it's possible to deal with this on a compiler which implements two-phase template instantiation, since the nullary function isn't a template function. It might be best just to remove it, since I don't think it's that useful anyway. Unless anyone's got a better idea. Daniel

On Thu, Nov 18, 2004 at 03:18:39PM +0000, Daniel James wrote:
Jonathan Wakely wrote:
In fact, I get a similar error for the example code in your mail:
overloaded.cc: In member function `ResultType GENERATE_DETAIL::foo_overloaded_t<ResultType>::operator()() const': overloaded.cc:7: error: no matching function for call to `foo()' overloaded.cc:4: note: candidates are: void foo(int) overloaded.cc:5: note: void foo(char*)
So although I can see uses for this, I can't use it :-)
Oh dear. I hadn't tested it very thoroughly - it works on g++ versions 2.95 and 3.3, but not 3.4 (which I guess you're using). I'm not sure
Yes, sorry, I should have said: GCC 3.4.3
it's possible to deal with this on a compiler which implements two-phase template instantiation, since the nullary function isn't a template
Yeah, I had a look at the implementation but couldn't stop it being compiled.
function. It might be best just to remove it, since I don't think it's that useful anyway. Unless anyone's got a better idea.
That makes sense to me (and makes the tests compile :) I suppose there might be cases where a model of Generator is overloaded but it's unlikely to be the biggest use case. Could you supply an extra arg to the macro, specifying whether to define the nullary overload for the cases where it is wanted and valid ? jon -- I eat my peas with honey, I've done it all my life It makes them taste quite funny, but it keeps them on the knife - The Orb

Jonathan Wakely wrote:
Could you supply an extra arg to the macro, specifying whether to define the nullary overload for the cases where it is wanted and valid ?
Yep, or maybe minimum, maximum parameter arguments. Although, if the macro gets complex enough to invoke, it'll probably be better just to write it out manually. For example, your tolower test becomes: #include <string> #include <algorithm> #include <cctype> struct { template <class T> T operator()(T x) { return std::tolower(x); } } tolower_visitor; int main() { std::string s("FNORD"); std::transform(s.begin(), s.end(), s.begin(), tolower_visitor); } Which is perhaps better since it has the correct return type. Daniel

On Thu, Nov 18, 2004 at 10:35:08PM +0000, Daniel James wrote:
Jonathan Wakely wrote:
Could you supply an extra arg to the macro, specifying whether to define the nullary overload for the cases where it is wanted and valid ?
Yep, or maybe minimum, maximum parameter arguments. Although, if the macro gets complex enough to invoke, it'll probably be better just to write it out manually. For example, your tolower test becomes:
#include <string> #include <algorithm> #include <cctype>
struct { template <class T> T operator()(T x) { return std::tolower(x); } } tolower_visitor;
int main() { std::string s("FNORD"); std::transform(s.begin(), s.end(), s.begin(), tolower_visitor); }
Which is perhaps better since it has the correct return type.
Indeed. It was the chance to avoid exactly that wrapper functor that interested me in your macro - but as you say, if the macro ends up taking many arguments it's simpler to explicitly define the functor. regards, jon -- "A sympathetic Scot summed it all up very neatly in the remark, 'You should make a point of trying every experience once, excepting incest and folk dancing.'" - Sir Arnold Bax

Daniel James wrote:
Jonathan Wakely wrote:
In fact, I get a similar error for the example code in your mail:
overloaded.cc: In member function `ResultType GENERATE_DETAIL::foo_overloaded_t<ResultType>::operator()() const': overloaded.cc:7: error: no matching function for call to `foo()' overloaded.cc:4: note: candidates are: void foo(int) overloaded.cc:5: note: void foo(char*)
So although I can see uses for this, I can't use it :-)
Oh dear. I hadn't tested it very thoroughly - it works on g++ versions 2.95 and 3.3, but not 3.4 (which I guess you're using).
And intel fails in strict mode as well. I've attached a quickly fixed version, which doesn't support nullary functions. I've also changed the interface to specify the object's name so that you can call 'std::tolower'. Your example now becomes: #include "overloaded.hpp" #include <string> #include <algorithm> #include <cctype> GENERATE_OVERLOADED(int, std::tolower, tolower_overloaded) int main() { std::string s("FNORD"); std::transform(s.begin(), s.end(), s.begin(), tolower_overloaded); } Which seems to work okay, and is probably a little better. Thanks for the feedback, Daniel

On 11/18/2004 07:00 AM, Daniel James wrote:
I've written a macro (the implementation is attached) for generating a function object for using overloaded functions with generic code such as the STL algorithms and boost::bind. A simple example of it's use: [snip] Any comments on this? Would anyone else find this useful? Also, has anyone done something similar? I'd be surprised if no one has, I always feel like I'm missing something when I'm doing this kind of thing.
The implementation is lacking in several ways - it doesn't work for non-const references, the return type is fixed, needs to deal with
I encountered the same problem with non-const references and the only work-around I found was to use mpl::vector<T0,T1,...,TN> as the 1st argument to the forwarding function. See: http://cvs.sourceforge.net/viewcvs.py/boost-sandbox/boost-sandbox/boost/managed_ptr/managed_ptr_ctor_forwarder.hpp?rev=1.1&view=auto and its use in overhead_referent_vals.hpp in that directory. Also, there's tests for 0 and 1 arguments in the corresponding libs/managed_ptr/test/smart_ptr_test.cpp. If the additional mpl::vector arg is not acceptable, maybe it could be curried away. I remember David Abraham had some currying code somewhere. Maybe it's in mpl also. HTH, Larry

Larry Evans wrote:
I encountered the same problem with non-const references and the only work-around I found was to use mpl::vector<T0,T1,...,TN> as the 1st argument to the forwarding function. See:
Thanks for the idea, but, in this case, if you need to supply the arguments, you might as well use Arturo Cuebas' method for selecting an overload [1]. Daniel [1] http://lists.boost.org/MailArchives/boost/msg10326.php
participants (3)
-
Daniel James
-
Jonathan Wakely
-
Larry Evans