Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert overloaded function to template functor

Tags:

c++

c++11

functor

I have a few overloaded functions, e.g.

int a(int) {/*...*/}
float a(float) {/*...*/}
/* ... */
int b(int) {/*...*/}
float b(float) {/*...*/}
/* ... */

My goal is to wrap these function into a functor object:

template <typename T>
struct func_a {
    auto T operator()(T t) -> decltype(a(t)) {return a(t);}
};

Is there a way to define the above template struct over some other template taking the overloaded function as argument? Something like this:

template </* pointer to an overloaded function f */>
struct create_functor {
    template <typename T>
    struct func {
        auto operator()() -> decltype(f(t)) {return f(t);}
    }
};

So I can generate the struct on compile-time, as in:

typedef create_functor<a>::func<int> func_a_int;
typedef create_functor<a>::func<float> func_a_float;
typedef create_functor<b>::func<int> func_a_int;
typedef create_functor<b>::func<float> func_a_float;
like image 910
Philipp H. Avatar asked Apr 28 '14 11:04

Philipp H.


2 Answers

You can define an overload set for each of your functions e.g :

int a(int i) {return 2*i;} 
float a(float d) {return 3*d;} 

#define overload_set(f, f_set) \
    struct f_set  { \
        template <typename... Args> \
        auto operator()(Args&&... args) \
            -> decltype(f(std::forward<Args>(args)...)) \
        { \
            return f(std::forward<Args>(args)...); \
        } \
    } 

overload_set(a, a_set);
// more overload_set here...

Using overload set instead of function pointer makes the "create_functor" implementation straightforward :

template <typename OverloadSet>
struct create_functor {
    template <typename... Args>
    struct func {
        auto operator()(Args... args) 
            -> decltype(OverloadSet{}(args...)) 
        {
            return OverloadSet{}(args...);
        }
    };
};

create_functor<a_set>::func<int> func_a_int; // Note: no need for typedef here
create_functor<a_set>::func<float> func_a_float;

int main()
{
   std::cout << func_a_int(2) << std::endl;
   std::cout << func_a_float(3.) << std::endl;
}
like image 68
Nicolas Avatar answered Oct 31 '22 11:10

Nicolas


As long as the signatures of the different overloads are as uniform as in your question, this can be done by using a function pointer value as template parameter:

template<typename T>
struct create_functor {
    template<T(*fct)(T)>
    struct functor {
        T operator()(T n) { return fct(n); }
    };
};

create_functor<int>::functor<a> func_a_int;
create_functor<float>::functor<a> func_a_float;

std::cout << func_a_int(42) << func_a_float(3.14f) << std::endl;
like image 26
ComicSansMS Avatar answered Oct 31 '22 13:10

ComicSansMS