Archived

This topic is now archived and is closed to further replies.

RuneLancer

Function Pointers...

Recommended Posts

Hiya! I''ve recently run into somewhat of an interesting issue. I''m writing a program to plot chaotic attractors (the what and how of these little buggers isn''t important for the purpose of this question though I''ll gladly elaborate) to further my understanding of the Win32 API (Mostly controls; I''ve limited myself mostly to simple full-screen graphic demos and games prior to this. Good understanding of the GDI and DirectX, though before this project I had no clue how, say, a listbox works). The program allows the user to choose a variety of "sets" to plot from a list. Now here''s my problem. Once the user selects a set and decides to plot it, there''s a bit of initialization where the parameters are initialized and a pointer to the function that calculates the attractor is returned. That way, instead of having a HUGE switch() block in my code, I can just include the attractors themselves in an other .cpp and not have to worry about them when working on the program itself. Only thing is, right now, I have over 60 attractors and a recent addition to the program means I''m probably going to easily double that number sometime soon. This is all fine and well but I''m starting to have a lot of prototyping in my .h and my function that returns a pointer to the attractor function is getting to be somewhat yucky too. Is there a way to make, I dunno, an array of functions, such as... void SAFunction[35] (parameters...) { } Or is there a better work-around? My code is getting a bit icky and kinda hard to manage, so I''m not really sure what to do other than either grin and bear it or find a better solution. I''ll gladly provide any additional information if necessary.

Share this post


Link to post
Share on other sites

  
std::map <std::string, boost::function<void(std::string)> > funcs;


this requires all functions accepting a string as parameter. the parameters can be stored in this string.
to fill the map do:


  
void test(std::string params)
{
if(! params.size())
{
printf("parameter required\n");
return;
}

std::vector<std::string> tokens;
tokenize(params, tokens, " ");

float param1, param2;

try
{
param1 = boost::lexical_cast<float>(tokens[0]);
param2 = boost::lexical_cast<float>(tokens[1]);
}
catch(boost::bad_lexical_cast)
{
printf("could not parse parameters\n");
}

printf("%f+%f = %f, %f-%f = %f\n", param1, param2, param1+param2, param1, param2, param1-param2);
}

aFunc(...)
{...
...
funcs["test"] = test;
...
funcs["test"]("5 543.76");
...
}



[edited by - 666_1337 on May 29, 2003 4:44:23 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
The Boost library doesn''t work very well on VC6 or VS.NET 2002. Works great under VS.NET 2003 though.

But why not use simple function pointers..

typedef void (*coolFunction)(int param1);

void coolFunc1(int param1)
{
..do stuff..
}

coolFunction functions[30] =
{
coolFunc1,coolFunc2,....
};

then

functions[3](6);

Share this post


Link to post
Share on other sites
this might serve as an example

header file

  
#ifndef __function_pointer_header_
#define __function_pointer_header_

#include <vector>
#include <map>
#include <string>
#include <boost/function.hpp>

class FunctionInterface
{
private:
std::map< std::string, boost::function<void(std::string) > > storedFunctions;
public:
FunctionInterface();
void addFunction(std::string, boost::function<void(std::string)> );
void callFunction(std::string);
};

#endif


source file

  
#include "../include/functionPointer.h"
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/bind.hpp>

void tokenize(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters)
{
std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
std::string::size_type pos = str.find_first_of(delimiters, lastPos);

while (std::string::npos != pos || std::string::npos != lastPos)
{
tokens.push_back(str.substr(lastPos, pos - lastPos));
lastPos = str.find_first_not_of(delimiters, pos);
pos = str.find_first_of(delimiters, lastPos);
}
}

FunctionInterface :: FunctionInterface()
{ ; }

void FunctionInterface :: addFunction(std::string func_name, boost::function<void(std::string)> func_pointer)
{
storedFunctions[func_name] = func_pointer;
}

void FunctionInterface :: callFunction(std::string command)
{
std::string parameter;
std::vector <std::string> parts;

tokenize(command, parts, " \n,");
if(parts.size() > 1)
{
for(int i = 1; i < parts.size(); i++)
parameter.append(parts[i]+" ");
}
if(storedFunctions[parts[0]])
storedFunctions[parts[0]](parameter);
else
printf("function not registred\n");
}

void test(std::string params)
{
if(! params.size())
{
printf("parameter required\n");
return;
}

std::vector<std::string> tokens;
tokenize(params, tokens, " ");

float param1, param2;

try
{
param1 = boost::lexical_cast<float>(tokens[0]);
param2 = boost::lexical_cast<float>(tokens[1]);
}
catch(boost::bad_lexical_cast)
{
printf("could not parse parameters\n");
}

printf("%f, %f, + = %f, - = %f\n", param1, param2, param1+param2, param1-param2);
}

class aTestClass
{
public:
void testFunc(std::string params)
{
std::cout << "memver function also works\n";
}
};

void quit(std::string params)
{
exit(0);
}

int main()
{
FunctionInterface f;
f.addFunction("test", test);
f.addFunction("quit", quit);
aTestClass a;
boost::function<void(std::string)> func = boost::bind(&aTestClass::testFunc, &a, _1);
f.addFunction("memberTest", func);


while(1)
{
printf("> ");
char buffer[80];
for(int i = 0; i < 79; i++)
{
buffer[i] = getc(stdin);
if(buffer[i] == ''\n'')
{
buffer[i+1] = ''\0'';
break;
}
}
f.callFunction(buffer);
}
return 0;
}

Share this post


Link to post
Share on other sites
Thanks, but I have absolutely no intention of using a library neither included with MSVC nor that I''ve ever heard of before. The other problem is that converting to and from a string would be way too taxing. These functions are called practically every other line in the drawing loop and need as little overhead as possible. Converting 5 parameters, two of which are pointers to the current X and Y position of the attractor and one a pointer to an array of parameters, to a string, passing it to the function, converting back into 4 parameters and an array of 14 parameter values, running the function, converting then back to string, returning them, then finally having the program make use of them after converting them again is something that sounds rather wasteful to me... The only alternative would be to use global variables.

Ah well, I suppose I should just grin and bear it. Adding new functions isn''t all that bad right now, it just makes for messy code. If I''m lucky, when I''ll start nearing the hundreds it won''t be too yucky (I''m at 73 right now and expect to easily go past 150).

Share this post


Link to post
Share on other sites