views:

654

answers:

9
+1  Q: 

C++ Function List

I'm working on a fairly complex project, a custom encryption routine if you will (just for fun) and I've run into this issue in designing my code layout.

I have a number of functions that I want to be able to call by index. Specifically, I need to be able to call one randomly for the encrypt process, but then address that by a specific index in the decrypt process.

I was considering a classic function array, but my main concern is that a function array would be tricky to maintain, and a little ugly. (The goal is to get each function pair in a separate file, to reduce compile times and make the code easier to manage.) Does anyone have a more elegant C++ solution as an alternative to a function array? Speed isn't really an issue, I'm more worried about maintainability.

-Nicholas

A: 

An object with an operator() method defined can act a lot like a function but be generally nicer to work with.

Khoth
+4  A: 

What's wrong with function array?

You need to call functions by index. So they must be put into some "indexable by index" structure somehow. Array is probably the simplest structure that suits this need.

Example (typing out of my head, might not compile):

struct FunctionPair {
   EncodeFunction encode;
   DecodeFunction decode;
};
FunctionPair g_Functions[] = {
   { MyEncode1, MyDecode1 },
   { MySuperEncode, MySuperDecode },
   { MyTurboEncode, MyTurboDecode },
};

What is "ugly" or "hard to maintain" in the approach above?

NeARAZ
A: 

Check this link out:

http://msdn.microsoft.com/en-us/library/kdte99aa.aspx

It's the C++ Function Call Operator: ().

Mark Ingram
If you're going to mark down, at least leave a comment...
Mark Ingram
+2  A: 

You could write something like:

class EncryptionFunction
{
public:
 virtual Foo Run(Bar input) = 0;
 virtual ~MyFunction() {}
};

class SomeSpecificEncryptionFunction : public EncryptionFunction
{
 // override the Run function
};

// ...

std::vector<EncryptionFunction*> functions;

// ...

functions[2]->Run(data);

You could use operator() instead of Run as the function name, if you prefer.

Khoth
A: 

Polymorphism could do the trick: you couldf follow the strategy pattern, considering each strategy to implement one of your functions (or a pair of them).

Then create a vector of strategies, and use this one instead of the function list.

But frankly, I don't see the problem with the function array; you can easily create a typedef to ease the readability. Effectifely, you will end up with exactly the same file structure when using the strategy pattern.

// functiontype.h
typedef bool (*forwardfunction)( double*, double* );

// f1.h
#include "functiontype.h"
bool f1( double*, double* );

// f1.c
#include "functiontype.h"
#include "f1.h"
bool f1( double* p1, double* p2 ) { return false; }


// functioncontainer.c    
#include "functiontype.h"
#include "f1.h"
#include "f2.h"
#include "f3.h"

forwardfunction my_functions[] = { f1, f2, f3 };
  • The function declaration and definitions are in separate files - compile time is ok.
  • The function grouping is in a separate file, having a dependency to the declarations only
xtofl
A: 

You could take a look at the Boost.Signals library. I believe it has the ability to call its registered functions using an index.

Jonas
A: 

Try Loki::Functor class. More info at CodeProject.com

Igor Semenov
A: 

If you looked in boost::signals library, you'll see an example very nice, that is very elegant:
Supose you have 4 functions like:
void print_sum(float x, float y)
{
std::cout << "The sum is " << x+y << std::endl;
}

void print_product(float x, float y)
{
std::cout << "The product is " << x*y << std::endl;
}

void print_difference(float x, float y)
{
std::cout << "The difference is " << x-y << std::endl;
}

void print_quotient(float x, float y)
{
std::cout << "The quotient is " << x/y << std::endl;
}

Then if you want to call them in a elegant way try:

boost::signal sig;

sig.connect(&print_sum);
sig.connect(&print_product);
sig.connect(&print_difference);
sig.connect(&print_quotient);

sig(5, 3);

And the output is:
The sum is 8
The product is 15
The difference is 2
The quotient is 1.66667

Eddie
Suggestion: use 'code sample' format for code samples. It's the ones-and-zeros button in the answer editor.
jwfearn
A: 

You need to use an array of function pointers. The only catch is that all the functions have to have basically the same prototype, only the name of the function and passed argument names can vary. The return type and argument types (as well as the number of arguments and order) must be identical.

int Proto1( void );
int Proto2( void );
int Proto3( void );

int (*functinPointer[3])( void ) =
{
   Proto1,
   Proto2,
   Proto3
};

Then you can do something like this:

int iFuncIdx = 0;
int iRetCode = functinPointer[iFuncIdx++]();
Jim Fell