Home > Back-end >  Sleek way to use template function as function argument?
Sleek way to use template function as function argument?

Time:08-16

What I really want to do is to compare the performance of different algorithms which solve the same task in different ways. Such algorithms, in my example called apply_10_times have sub algorithms, which shall be switchable, and also receive template arguments. They are called apply_x and apply_y in my example and get int SOMETHING as template argument.

I think the solution would be to specify a template function as template parameter to another template function. Something like this, where template_function is of course pseudo-code:

template<int SOMETHING>
inline void apply_x(int &a, int &b) {
    // ...
}

template<int SOMETHING>
inline void apply_y(int &a, int &b) {
    // ...
}

template<template_function APPLY_FUNCTION, int SOMETHING>
void apply_10_times(int &a, int &b) {
    for (int i = 0; i < 10; i  ) {
        cout << SOMETHING; // SOMETHING gets used here directly as well

        APPLY_FUNCTION<SOMETHING>(a, b);
    }
}

int main() {
    int a = 4;
    int b = 7;
    apply_10_times<apply_x, 17>(a, b);
    apply_10_times<apply_y, 19>(a, b);
    apply_10_times<apply_x, 3>(a, b);
    apply_10_times<apply_y, 2>(a, b);

    return 0;
}

I've read that it's not possible to pass a template function as a template parameter, so I can't pass APPLY_FUNCTION this way. The solution, afaik, is to use a wrapping struct, which is then called a functor, and pass the functor as a template argument. Here is what I got with this approach:

template<int SOMETHING>
struct apply_x_functor {
    static inline void apply(int &a, int &b) {
        // ...
    }
};

template<int SOMETHING>
struct apply_y_functor {
    static inline void apply(int &a, int &b) {
        // ...
    }
};

template<typename APPLY_FUNCTOR, int SOMETHING>
void apply_10_times(int &a, int &b) {
    for (int i = 0; i < 10; i  ) {
        cout << SOMETHING; // SOMETHING gets used here directly as well
        APPLY_FUNCTOR:: template apply<SOMETHING>(a, b);
    }
}

This approach apparently works. However, the line APPLY_FUNCTOR:: template apply<SOMETHING>(a, b); looks rather ugly to me. I'd prefer to use something like APPLY_FUNCTOR<SOMETHING>(a, b); and in fact this seems possible by overloading the operator(), but I couldn't get this to work. Is it possible and if so, how?

CodePudding user response:

As it is not clear why you need APPLY_FUNCTION and SOMETHING as separate template arguments, or why you need them as template arguments at all, I'll state the obvious solution, which maybe isn't applicable to your real case, but to the code in the question it is.

#include <iostream>

template<int SOMETHING>
inline void apply_x(int a, int b) {
    std::cout << a << " " << b;
}

template<int SOMETHING>
inline void apply_y(int a, int b) {
    std::cout << a << " " << b;
}

template<typename F>
void apply_10_times(int a, int b,F f) {
    for (int i = 0; i < 10; i  ) {
        f(a, b);
    }
}

int main() {
    int a = 4;
    int b = 7;
    apply_10_times(a, b,apply_x<17>);
    apply_10_times(a, b,apply_y<24>);
}

If you want to keep the function to be called as template argument you can use a function pointer as non-type template argument:

template<void(*F)(int,int)>
void apply_10_times(int a, int b) {
    for (int i = 0; i < 10; i  ) {
        F(a, b);
    }
}

int main() {
    int a = 4;
    int b = 7;
    apply_10_times<apply_x<17>>(a, b);
    apply_10_times<apply_y<24>>(a, b);
}

In any case I see no reason to have APPLY_FUNCTION and SOMETHING as separate template arguments. The only gain is more complex syntax which is exactly what you want to avoid. If you do need to infer SOMETHING from an instantiation of either apply_x or apply_y, this is also doable without passing the template and its argument separately, though again you'd need to use class templates rather than function templates.


PS:

Ah, now I understand what you mean. Yes, apply_10_times() also uses SOMETHING directly. Sorry, I simplified the code in the question too much.

As mentioned above. This does still not imply that you need to pass them separately. You can deduce SOMETHING from a apply_x<SOMETHING> via partial template specialization. This however requires to use class templates not function templates:

#include <iostream>

template <int SOMETHING>
struct foo {};

template <int X>
struct bar {};

template <typename T>
struct SOMETHING;

template <template <int> class T,int V>
struct SOMETHING<T<V>> { static constexpr int value = V; };

int main() {
    std::cout << SOMETHING< foo<42>>::value;
    std::cout << SOMETHING< bar<42>>::value;
}

CodePudding user response:

What I really want to do is to compare the performance of different algorithms which solve the same task in different ways.

You should provide more details about that.

Your first step should be get familiar with Google Benchmark. There is as site which provides it online. This tool give proper patterns for your scenario.

In next step you must be aware that in C and C there is "as if rule" which allows optimizer do do wonderful things, but makes creation of good performance test extremely difficult. It is easy write test which doesn't measure actual production code.

Here is cppcon talk showing how many traps are hidden when doing a good performance test fro C code. So be very very careful.

  • Related