A container of functions ?

Started by
15 comments, last by Ey-Lord 19 years ago
Hi ! What do i want? I wanna be able to build/fill ect.. a container ( stl ? ) with functions, and after that, just parse it, and call every of those fontions ... For exemple . Magic_container.push( printf("hihi") ); Magic_container.push( glColor3ub(0,0,0) ); Magic_container.push( font->draw() ); ect ... and i reaaly dunno how to start to do that thx
Advertisement
Functions are not first class objects in C++. The best you can get natively are function pointers. There are libraries that expand on that, letting you store function pointers and their bound parameters - a bit like what you're trying to achieve. Furthermore, C++ containers are homogeneous containers. Even with the above-mentioned libraries, you will only be able to store function objects which have identical signatures (after binding of parameters).

An example:

#include <boost/function.hpp>#include <boost/bind.hpp>#include <vector>using namespace std;using namespace boost;typedef function<void (void)> func_t;vector<func_t> vec;vec.push_back( bind(printf, "hihi")      ); // might not work, printf is variadic.vec.push_back( bind(glColor3ub, 0, 0, 0) );vec.push_back( bind(&Font::draw, font)   ); // The & is required for member functions.


Look at boost::bind for more details.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Generally, one would have to use function pointers, and store those in the container. However, one cannot mix different function types in the same container.

To do something akin to what you want, you will have to basically set aside a numeric value for a particular function, and then store integers in your container... ie:

#define PRINTF_FUNC_TOKEN 0#define GL_BLAH_FUNC_TOKEN 1#define FONT_DRAW_FUNC_TOKEN 2container.push_back(PRINTF_FUNC_TOKEN);container.push_back(GL_BLAH_FUNC_TOKEN);container.push_back(FONT_DRAW_FUNC_TOKEN);for(size_t i = 0; i < container.size(); i++){  switch(container)  {    case PRINTF_FUNC_TOKEN:        printf("hihi");        break;    // etc  }}container.clear();
thx to you both !
@AP, yup its a way to do so, but i'll have MANY case ( because many param ...) may not be a good solution :)
@Fruny

humm boost ;o) i reemenber i spend many hours trying to install this ( i'm VERY bad at installing new libs ... ) when i was under devc++, now im under vc++, i may try again :)

if i understood your exemple, it does pretty well what i want, exept maybe that i can only stor function with void in retun type? ( -> a new container for every return type ? ) its not a big deal for what im doing now i think ...but i'd better be sure :)

edit : and when i want to parse my vector and exetute all those functions, how to i do ?
thx
write a base class with a pure virtual function void call(),
then write derived classes for each function signature you need to support, holding a function pointer....
Quote:Original post by Ey-Lord
thx to you both !
@AP, yup its a way to do so, but i'll have MANY case ( because many param ...) may not be a good solution :)
@Fruny

humm boost ;o) i reemenber i spend many hours trying to install this ( i'm VERY bad at installing new libs ... ) when i was under devc++, now im under vc++, i may try again :)


1.32 seems to have an EXE installer (havn't actually tried it myself yet). Also, if your issue was with trying to build Boost.Jam because you saw no executable for windows, I'd like to point out that "Download boost-jam-3.1.10-1-ntx86.zip" is the windows version :). (This can be downloaded from here , the installation guide can be found here (under "Getting Started" from the main page).

Quote:if i understood your exemple, it does pretty well what i want, exept maybe that i can only stor function with void in retun type? ( -> a new container for every return type ? ) its not a big deal for what im doing now i think ...but i'd better be sure :)


I don't believe that's necessary, I believe the return type will be appropriately discarded.

Quote:edit : and when i want to parse my vector and exetute all those functions, how to i do ?
thx


Well, here's one way:

struct do_call{    void operator()( const boost::function< void ( void ) > & f ) const    {        f();    }};std::for_each( vec.begin() , vec.end() , do_call() );


Or to be less idiomatic (read: to better explain boost::function):
EDIT: Not really better at explaining, if anything, it's worse. Removed.

More reading:

http://www.boost.org/index.htm
http://www.boost.org/libs/libraries.htm
http://www.boost.org/doc/html/function.html
http://www.boost.org/libs/bind/bind.html
Random thought: perhaps greater flexibility could be acheived using boost::lambda?
What your really want out of boost is Boost.Signals
Quote:humm boost ;o) i reemenber i spend many hours trying to install this ( i'm VERY bad at installing new libs ... ) when i was under devc++, now im under vc++, i may try again :)


This part of the library doesn't require any installation. If you really want you can just copy the whole /boost directory (the one where the header files are) into your compiler's /include directory (so that you have /include/boost), and it'll work. Only some library components require compilation, most of boost exists as header files as the C++ library does.

Quote:if i understood your exemple, it does pretty well what i want, exept maybe that i can only stor function with void in retun type? ( -> a new container for every return type ? )


You need a container for each final function signature. i.e. different type or number of unbound parameters, different return type. Different function signatures are supported; just not all in the same container.

Quote:
edit : and when i want to parse my vector and exetute all those functions, how to i do ?


You just call them: for(int i=0; i<vec.size; ++i) vec();

If you want functions with unbound parameters (which you specify when you finally decide to execute the functions), check the link I posted above.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Quote:Original post by Fruny
This part of the library doesn't require any installation. If you really want you can just copy the whole /boost directory (the one where the header files are) into your compiler's /include directory (so that you have /include/boost), and it'll work. Only some library components require compilation, most of boost exists as header files as the C++ library does.

Quote:if i understood your exemple, it does pretty well what i want, exept maybe that i can only stor function with void in retun type? ( -> a new container for every return type ? )


You need a container for each final function signature. i.e. different type or number of unbound parameters, different return type. Different function signatures are supported; just not all in the same container.


Boost is slightly more flexible than you think...

main.cc:
#include <iostream>#include <boost/function.hpp>#include <boost/bind.hpp>using namespace boost;using namespace std;double display_and_return_pi( void ){	double pi = 3.14159265359;	cout << pi << endl;	return pi;}boost::function< void ( void ) > f;int main ( void ){	f = bind( display_and_return_pi );	f();}


make -k all 'Building file: ../main.cc'g++ -O0 -g3 -Wall -c -fmessage-length=0 -omain.o ../main.cc'Finished building: ../main.cc'' ''Building target: test.5.exe'g++  -o test.5.exe   main.o      'Finished building: test.5.exe'Build complete for project test.5


C:\eclipse\workspace\test.5\Debug>test.53.14159C:\eclipse\workspace\test.5\Debug>


Unless you meant that you're unable to do this:

boost::function< void ( void ) > f = display_and_return_pi;double pi = f();


In which case you're completely right :).

This topic is closed to new replies.

Advertisement