tags:

views:

285

answers:

4

I have a template function where the template parameter is an integer. In my program I need to call the function with a small integer that is determined at run time. By hand I can make a table, for example:

void (*f_table[3])(void) = {f<0>,f<1>,f<2>};

and call my function with

f_table[i]();

Now, the question is if there is some automatic way to build this table to arbitrary order. The best I can come up with is to use a macro

#define TEMPLATE_TAB(n) {n<0>,n<1>,n<2>}

which at leasts avoids repeating the function name over and over (my real functions have longer names than "f"). However, the maximum allowed order is still hard coded. Ideally the table size should only be determined by a single parameter in the code. Would it be possible to solve this problem using templates?

+3  A: 

[Proven wrong: I don't think that can be done purely with templates.]

Take a look at the boost preprocessor library.

David Rodríguez - dribeas
Thank you! BOOST_PP_ENUM_PARAMS seems to be exactly what I need.
uekstrom
It _can_ be done.
xtofl
+6  A: 

It can be done by 'recursive' dispatching: a template function can check if it's runtime argument matches it's template argument, and return the target function with the template argument.

#include <iostream>
template< int i > int tdispatch() { return i; }

// metaprogramming to generate runtime dispatcher of 
// required size:
template< int i > int r_dispatch( int ai ) {
    if( ai == i ) {
      return tdispatch< i > ();
    } else {
      return r_dispatch< i-1 >( ai );
    }
}
template<> int r_dispatch<-1>( int ){ return -1; }

// non-metaprogramming wrapper
int dispatch( int i ) { return r_dispatch<100>(i); }

int main() {
   std::cout << dispatch( 10 );
   return 0;
}
xtofl
This is very nice! Do you know any way to do it without the linear cost to find the right function?
uekstrom
@uekstrom: it can be optimized by getting e.g. binary search in place, but I can't shake that one out of my sleeve right now.
xtofl
@dribeas: the metaprogramming part can, though, be strictly separated from the regular programming part, as shown by my edit.
xtofl
@uekstrom: I added another answer to generate a lookup table by using a template. This should be equally fast as the explicit approach you started with.
xtofl
+4  A: 

You can create a template that initializes a lookup table by using recursion; then you can call the i-th function by looking up the function in the table:

#include <iostream>

// recursive template function to fill up dispatch table
template< int i > bool dispatch_init( fpointer* pTable ) {
  pTable[ i ] = &function<i>;
  return dispatch_init< i - 1 >( pTable );
}

// edge case of recursion
template<> bool dispatch_init<-1>() { return true; }

// call the recursive function
const bool initialized = dispatch_init< _countof(ftable) >( ftable );


// the template function to be dispatched
template< int i > void function() { std::cout << i; }


// dispatch functionality: a table and a function
typedef void (*fpointer)();    
fpointer ftable[100];

void dispatch( int i ){ return (ftable[i])(); }


int main() {
  dispatch( 10 );
}
xtofl
Thanks! This is perfect for my needs. I will macrofy it over "function", because I have a bunch of functions that need to be tabulated.
uekstrom
+1 nice solution
David Rodríguez - dribeas
+1 Like your solutions ... A new fan is born ? ;-)
neuro
A: 

Following xtofl I decided to go with the following macro/template solution shown below. I needed the macro because I want to build these dispatch tables for many functions, and I cannot see how to do that with one single template function.

#include <iostream>

using namespace std;

#define MAX_ORDER 8

#define DISPATCH_TABLE(table,fpointer,function,N)      \
template< int i > fpointer *function##dispatch_init(fpointer function_table[]) \
{ \
  function_table[i] = function<i>; \
  return function##dispatch_init< i - 1 >(function_table); \
} \
template<> fpointer *function##dispatch_init<-1>(fpointer function_table[]) \
{  \
  return function_table; \
} \
const fpointer *table = function##dispatch_init<N>(new fpointer[N])

typedef void (*fpointer)(void);

template<int N>
void printN(void)
{
  cout << N << endl;
}

DISPATCH_TABLE(printN_table, fpointer, printN, MAX_ORDER);

int main(void)
{
  for (int i = 0; i < MAX_ORDER; i++)
    printN_table[i]();
  return 0;
}
uekstrom