Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 704
HighCommander4 Avatar asked Aug 11 '11 22:08

HighCommander4


2 Answers

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.

like image 117
Luc Danton Avatar answered Nov 12 '22 03:11

Luc Danton


Why couldn't you use template template parameters? You said you can't pass your template uninstantiated, but I'm not sure if you've heard of this before, tell me if you have and it won't work.

I don't know what your code structure looks like, but can you do something like

I know this works, don't know if it's what yo uwant though:

template<typename T>
T some_algorithm(T data) { return T(); } // just returning nothing for example

template<typename T, T(*Something)(T)>
class FuncClass {
public:
    T run(T data) { return Something(data); }
};

template<typename T, typename Functor>
void apply_algorithm(T data) {
    Functor F;
    F.run(data);
}

int main() {
    int mydata = 4;
    apply_algorithm<int, FuncClass<int, some_algorithm<int> > >(mydata);

    cin.get();
}
like image 1
Seth Carnegie Avatar answered Nov 12 '22 01:11

Seth Carnegie