Search code examples
c++templatesstatic-polymorphismfunction-template

Is there a generic way to adapt a function template to be a polymorphic function object?


I have some function templates, for example

template <typename T>
void foo(T);

template <typename T>
void bar(T);

// others

and I need to pass each one to an algorithm that will call it with various types, e.g.

template <typename F>
void some_algorithm(F f)
{
    // call f with argument of type int
    // call f with argument of type SomeClass
    // etc.
}

I can't pass in my function template uninstantiated, but I can't instantiate it with any specific type either because some_algorithm will need to call it with arguments of several different types.

I could adapt my function templates to be polymorphic function objects, e.g.

struct foo_polymorphic
{
    template <typename T>
    void operator()(T t)
    {
        foo(t);
    }
};

and then pass it as some_algorithm(foo_polymorphic()). But this requires writing a separate adapter for each of my function templates.

Is there a generic way of adapting a function template to be a polymorphic function object, i.e. some mechanism that I can re-use for each of the function templates I need to adapt, without having to declare something separately for each one?


Solution

  • The short version of the problem is given an overloaded name f, how to concisely write an object ff such that ff(a0, a1, a2, ...) ultimately calls f(a0, a1, a2, ...).

    A polymorphic functor, how you point out yourself, is the usual solution. But it must be defined out of line (since it has a template member), so I'll consder that not concise enough for the purposes of my answer.

    Currently lambda expressions yield a monomorphic functor, so they're close but not quite there.

    // set of functions overloaded on int and double
    void f(int);
    void f(double);
    
    auto ff = [](int i) { return f(i); };
    

    As GMan pointed out in the comments polymorphic lambdas would (should?) be the solution to concisely write polymorphic functors inline.

    In the meantime, it is possible to write a make_overload helper that combines multiple functors into one, such that

    auto ff = make_overload(
        [](int arg0) { return f(arg0); }
        , [](double arg0) { return f(arg0); } );
    

    would 'capture' the whole overload set. Perhaps a Boost.Preprocessor macro could help here, so that auto ff = POLYMORPHIC_LAMBDA( 1, (int)(double), { return f(arg0); } ); be used inline. I suspect there are arity restrictions however (hence the first macro argument), unlike the usual out-of-line hand-written polymorphic functor solution; so this wouldn't help with e.g. variadic function templates.