jiandingzhe
jiandingzhe

Reputation: 2121

How to achieve compile time polymorphism of several functions?

It seems I should to use function as a template argument, but it cannot be done in such way.

The header file looks like this:

foo_out_type foo(foo_in_type input);
baz_out_type bar(bar_in_type input);

template<typename T_IN, typename T_OUT>
void do_list(const vector<T_IN>& input,
             vector<T_OUT>& output);

// I want to specialize the template code at compile time
// So the users don't need to compile the code everytime
template<>
void do_list<foo_in_type, foo_out_type>(const vector<foo_in_type>& input,
                                        vector<foo_out_type>& output);

template<>
void do_list<bar_in_type, bar_out_type>(const vector<bar_in_type>& input,
                                        vector<bar_out_type>& output);

The implementation file looks like this:

template<typename T_IN, typename T_OUT, typename T_FUNC>
void __do_list_impl__(const vector<T_IN>& input,
                      vector<T_OUT>& output)
{
    for (size_t i=0; i<input.size(); i++)
        output.push_back(T_FUNC(input[i]));
}

template<>
void do_list<foo_in_type, foo_out_type>(const vector<foo_in_type>& input,
                                        vector<foo_out_type>& output)
{
    __do_list_impl__<foo_in_type, foo_out_type, do_foo>(input, output);
}

template<>
void do_list<bar_in_type, bar_out_type>(const vector<bar_in_type>& input,
                                        vector<bar_out_type>& output)
{
    __do_list_impl__<bar_in_type, bar_out_type, do_bar>(input, output);
}

The key is: I don't want to write the implementation several times, as the actual code is much more complex than this. However, the function cannot be passed as an template argument.

So, how should I work around this?

Upvotes: 2

Views: 108

Answers (2)

Stefano Buora
Stefano Buora

Reputation: 1062

You just have to use functor instead of a function.

Instead of declaring your body function as:

T_OUT do_foo(T_IN& input) {
  //your job
}

declare it as an object type:

class do_foo {
  public:
    T_OUT operator()(T_IN& input) {
     //place your job code here
  }
};

Then change your do_list implementation from:

template<typename T_IN, typename T_OUT, typename T_FUNC>
void __do_list_impl__(const vector<T_IN>& input,
                      vector<T_OUT>& output)
{
    for (size_t i=0; i<input.size(); i++)
        output.push_back(T_FUNC(input[i]));
}

to:

template<typename T_IN, typename T_OUT, typename T_FUNCTOR>
void __do_list_impl__(const vector<T_IN>& input,
                      vector<T_OUT>& output)
{
    T_FUNCTOR myFunctor;
    for (size_t i=0; i<input.size(); i++)
        output.push_back(myFunctor(input[i]));
}

Obviously create a new class also for the "do_bar" function

Upvotes: 1

Joshua Chia
Joshua Chia

Reputation: 1968

Assuming you only have a small number of specialized versions of do_list<...>()...

In your header:

  1. Specialize different versions of do_list<...>() to call different non-template helper functions do_list_impl1(), do_list_impl2(), ...
  2. Also, declare non-template functions do_list_impl1(), do_list_impl2(), ...

In your implementation file:

  1. Include the definition for the template function __do_list_impl__()
  2. Define do_list_impl1() et al to just call __do_list_impl__() with appropriate template arguments.

Upvotes: 0

Related Questions