[functional] [overloaded_function] polymorphic functions?

Hello all, I spent some time trying to make overloaded_function support polymorphic functions but I had little success :( 1) I was able to do this (see code below): overloaded_function< void (int) , functor<poly, void (generic)> > o(f, p); o(321); o(3.21); o("cba"); But I don't like it because I explicitly have to pass the functor type poly. I wanted instead to only use generic to tag the template parameters in the signature: overloaded_function< void (int) , void (generic) > o(f, p); o(321); o(3.21); o("cba"); I'd consider this acceptable but I wasn't able to program this because I loose p's type (poly) in base so base cannot hold a reference to the functor p... Is there a way around this? (Some type-erasure magic maybe??) 2) I don't think this can work with function templates because in order to get a pointer to a function template you have to instantiate it: g<char*> Now I can get the function pointer but it's not polymorphic anymore... 3) I don't think there is any way to implement make_overloaded_function with polymorphic types because I can't re-construct the function signature from the functor given that its operator contains template parameters... I have no idea on how to work around this... If you have suggestions for 1, 2, or 3), they are welcome. Otherwise, it seems that supporting polymorphic functions in overloaded_function is not really feasible... The little I got so far: #include <boost/function.hpp> #include <boost/type_traits/function_traits.hpp> #include <iostream> void f(int x) { std::cout << x << std::endl; } template<typename T> void g(T x) { std::cout << x << std::endl; } struct poly { template<typename T> void operator()(T x) { std::cout << x << std::endl; } }; template<typename F> struct base { template<typename G> base(G g) : f_(g) {} typename boost::function_traits<F>::result_type operator()( typename boost::function_traits<F>::arg1_type arg1 ) { return f_(arg1); } private: boost::function<F> f_; }; struct generic; template<typename Ftor, typename F> struct functor; template<typename Ftor, typename R> struct base< functor<Ftor, R (generic)> > { base(Ftor& ftor) : ftor_(ftor) {} template<typename Arg1> R operator()(Arg1 arg1) { return ftor_(arg1); } private: Ftor& ftor_; }; template<typename F1, typename F2> struct overloaded_function : base<F1>, base<F2> { template<typename G1, typename G2> overloaded_function(G1 g1, G2 g2) : base<F1>(g1), base<F2>(g2) {} using base<F1>::operator(); using base<F2>::operator(); }; int main() { f(123); g("xyz"); boost::function<void (char*)> gg = g<char*>; poly p; p(1.23); p("abc"); overloaded_function< void (int) , functor<poly, void (generic)> > o(f, p); o(321); o(3.21); o("cba"); return 0; } Thanks a lot. --Lorenzo

On Fri, Feb 17, 2012 at 10:16 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
Hello all,
I spent some time trying to make overloaded_function support polymorphic functions but I had little success :(
1) I was able to do this (see code below):
overloaded_function< void (int) , functor<poly, void (generic)> > o(f, p); o(321); o(3.21); o("cba");
But I don't like it because I explicitly have to pass the functor type poly. I wanted instead to only use generic to tag the template parameters in the signature:
overloaded_function< void (int) , void (generic) > o(f, p); o(321); o(3.21); o("cba");
I'd consider this acceptable but I wasn't able to program this because I loose p's type (poly) in base so base cannot hold a reference to the functor p... Is there a way around this? (Some type-erasure magic maybe??)
Actually, with the small change base<R (Ftor::*)(generic)> I can do this: overloaded_function< void (int) , void (poly::*)(generic) > o(f, p); o(321); o(3.21); o("cba"); Which looks better to me than using functor<poly, void (generic)> but still: Is there any way I can get rid of specifying the functor type poly completely?
2) I don't think this can work with function templates because in order to get a pointer to a function template you have to instantiate it:
g<char*>
Now I can get the function pointer but it's not polymorphic anymore...
3) I don't think there is any way to implement make_overloaded_function with polymorphic types because I can't re-construct the function signature from the functor given that its operator contains template parameters... I have no idea on how to work around this...
If you have suggestions for 1, 2, or 3), they are welcome. Otherwise, it seems that supporting polymorphic functions in overloaded_function is not really feasible...
The little I got so far:
#include <boost/function.hpp> #include <boost/type_traits/function_traits.hpp> #include <iostream>
void f(int x) { std::cout << x << std::endl; }
template<typename T> void g(T x) { std::cout << x << std::endl; }
struct poly { template<typename T> void operator()(T x) { std::cout << x << std::endl; } };
template<typename F> struct base { template<typename G> base(G g) : f_(g) {}
typename boost::function_traits<F>::result_type operator()( typename boost::function_traits<F>::arg1_type arg1 ) { return f_(arg1); }
private: boost::function<F> f_; };
struct generic;
template<typename Ftor, typename F> struct functor;
template<typename Ftor, typename R> struct base< functor<Ftor, R (generic)> > { base(Ftor& ftor) : ftor_(ftor) {}
template<typename Arg1> R operator()(Arg1 arg1) { return ftor_(arg1); } private: Ftor& ftor_; };
template<typename F1, typename F2> struct overloaded_function : base<F1>, base<F2> { template<typename G1, typename G2> overloaded_function(G1 g1, G2 g2) : base<F1>(g1), base<F2>(g2) {}
using base<F1>::operator(); using base<F2>::operator(); };
int main() { f(123); g("xyz"); boost::function<void (char*)> gg = g<char*>;
poly p; p(1.23); p("abc");
overloaded_function< void (int) , functor<poly, void (generic)> > o(f, p); o(321); o(3.21); o("cba");
return 0; }
--Lorenzo

On 18/02/12 03:16, Lorenzo Caminiti wrote:
Hello all,
I spent some time trying to make overloaded_function support polymorphic functions but I had little success :(
1) I was able to do this (see code below):
overloaded_function< void (int) , functor<poly, void (generic)> > o(f, p); o(321); o(3.21); o("cba");
But I don't like it because I explicitly have to pass the functor type poly. I wanted instead to only use generic to tag the template parameters in the signature:
overloaded_function< void (int) , void (generic) > o(f, p); o(321); o(3.21); o("cba");
I'd consider this acceptable but I wasn't able to program this because I loose p's type (poly) in base so base cannot hold a reference to the functor p... Is there a way around this? (Some type-erasure magic maybe??)
If the type of o did not involve poly, then you could pass a reference to o to another translation unit where the definition of poly was not visible. In that other translation unit you could call it with an arbitrary type, which would have to instantiate poly::operator() without sight of its definition. Therefore, I conclude that this is clearly impossible.
2) I don't think this can work with function templates because in order to get a pointer to a function template you have to instantiate it:
g<char*>
Now I can get the function pointer but it's not polymorphic anymore...
Indeed. We can hope perhaps that some hypothetical future support for polymorphic lambdas would help here, but even that only reduces it to the problem of function objects.
3) I don't think there is any way to implement make_overloaded_function with polymorphic types because I can't re-construct the function signature from the functor given that its operator contains template parameters... I have no idea on how to work around this...
Indeed. Even TTI struggled in this arena: http://svn.boost.org/svn/boost/sandbox/tti/libs/tti/doc/html/the_type_traits...
If you have suggestions for 1, 2, or 3), they are welcome. Otherwise, it seems that supporting polymorphic functions in overloaded_function is not really feasible...
FWIW, I concur. I applaud your efforts, but I think this was always a long shot. John

Hi Lorenzo, On Feb 18, 2012, at 6:24 AM, John Bytheway wrote:
On 18/02/12 03:16, Lorenzo Caminiti wrote:
I spent some time trying to make overloaded_function support polymorphic functions but I had little success :(
Thank you for attempting it! This is something that came up as a possible better solution in the Conversion review in August. (For which my report is grievously late but not forgotten.)
1) I was able to do this (see code below):
overloaded_function< void (int) , functor<poly, void (generic)>
o(f, p); o(321); o(3.21); o("cba");
But I don't like it because I explicitly have to pass the functor type poly. I wanted instead to only use generic to tag the template parameters in the signature:
overloaded_function< void (int) , void (generic)
o(f, p); o(321); o(3.21); o("cba");
I'd consider this acceptable but I wasn't able to program this because I loose p's type (poly) in base so base cannot hold a reference to the functor p... Is there a way around this? (Some type-erasure magic maybe??)
If the type of o did not involve poly, then you could pass a reference to o to another translation unit where the definition of poly was not visible. In that other translation unit you could call it with an arbitrary type, which would have to instantiate poly::operator() without sight of its definition. Therefore, I conclude that this is clearly impossible.
I had neglected the fact that overloaded_function does type erasure (duh). I guess this would only be possible if the polymorphic result_of (or equivalent) is passed to overloaded_function. Probably not worth it. Sorry if I sent you on a wild goose chase! I really appreciate the effort, and knowing that this technique could be used as long as type erasure is not required (as it isn't for Conversion). Cheers, Gordon

on Wed Mar 14 2012, Gordon Woodhull <gordon-AT-woodhull.com> wrote:
If the type of o did not involve poly, then you could pass a reference to o to another translation unit where the definition of poly was not visible. In that other translation unit you could call it with an arbitrary type, which would have to instantiate poly::operator() without sight of its definition. Therefore, I conclude that this is clearly impossible.
I had neglected the fact that overloaded_function does type erasure (duh). I guess this would only be possible if the polymorphic result_of (or equivalent) is passed to overloaded_function. Probably not worth it.
I think Lorenzo's assessment ("not possible") is more accurate. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Mar 14, 2012, at 6:33 PM, Dave Abrahams wrote:
on Wed Mar 14 2012, Gordon Woodhull <gordon-AT-woodhull.com> wrote:
If the type of o did not involve poly, then you could pass a reference to o to another translation unit where the definition of poly was not visible. In that other translation unit you could call it with an arbitrary type, which would have to instantiate poly::operator() without sight of its definition. Therefore, I conclude that this is clearly impossible.
I had neglected the fact that overloaded_function does type erasure (duh). I guess this would only be possible if the polymorphic result_of (or equivalent) is passed to overloaded_function. Probably not worth it.
I think Lorenzo's assessment ("not possible") is more accurate.
Right, on further thought, I think this would require templated virtual methods, which are impossible as far as I know. That might be the most succinct way of putting it. Of course, this still wouldn't preclude a non-type-erased polymorphic function overloader. Cheers, Gordon
participants (4)
-
Dave Abrahams
-
Gordon Woodhull
-
John Bytheway
-
Lorenzo Caminiti