A container of functions ?

Recommended Posts

Ey-Lord    225
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

Share on other sites
Fruny    1658
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.

Share on other sites
Guest Anonymous Poster
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[i])  {    case PRINTF_FUNC_TOKEN:        printf("hihi");        break;    // etc  }}container.clear();

Share on other sites
Ey-Lord    225
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

Share on other sites
Guest Anonymous Poster
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....

Share on other sites
MaulingMonkey    1730
Quote:
 Original post by Ey-Lordthx 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 :) @Frunyhumm 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.

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

Share on other sites
Zahlman    1682
Random thought: perhaps greater flexibility could be acheived using boost::lambda?

Share on other sites
What your really want out of boost is Boost.Signals

Share on other sites
Fruny    1658
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[i]();

If you want functions with unbound parameters (which you specify when you finally decide to execute the functions), check the link I posted above.

Share on other sites
MaulingMonkey    1730
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 :).

Share on other sites
Fruny    1658
Quote:
 Original post by MaulingMonkeyUnless 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 :).

Precisely. You're constrained by the function type you parameterize the container with. If you want to effectively use different types, you need separate containers; otherwise they'll all "look the same".

[Edited by - Fruny on March 29, 2005 5:19:46 PM]

Share on other sites
Ey-Lord    225
Thx a lot for all of this ! i just read it fast because im goign to school, when i'll be back, i'll try to donwload / install boost and try some of the solutions u offered me :)

Share on other sites
Ey-Lord    225
I just downloaded boost, and copy/paste the boost file in my include directory .
I included boost/bind.hpp and boost/function.cpp
I made a new var : std::vector< boost::function<void (void)> > vec ;
and when i try to add something to this vecotr, i got an error :

vec.push_back( boost::bind(glColor3ub, 0, 0, 0) );

Errors are all in bind.hpp ... its wierd !
c:\Microsoft Visual Studio .NET 2003\Vc7\include\boost\bind.hpp(62): error C2039: 'result_type' : is not a member of 'operatorglobal namespace'''c:\Microsoft Visual Studio .NET 2003\Vc7\include\boost\bind.hpp(62): error C2146: syntax error : missing ';' before identifier 'type'c:\Microsoft Visual Studio .NET 2003\Vc7\include\boost\bind.hpp(62): error C2825: 'F::result_type': cannot form a qualified namec:\Microsoft Visual Studio .NET 2003\Vc7\include\boost\bind.hpp(62): error C2955: 'boost::_bi::type' : use of class template requires template argument listc:\Microsoft Visual Studio .NET 2003\Vc7\include\boost\bind.hpp(62): fatal error C1903: unable to recover from previous error(s); stopping compilation

I tried to google those error .... didnt find anything special .

Share on other sites
kingnosis    267
Quote:
 Original post by Anonymous Posterwrite a base class with a pure virtual function void call(),then write derived classes for each function signature you need to support

This was the first solution that occured to me.

Perhaps I'm wrong, but this minor abuse of polymorphism is a lot more direct and flexible than trying to trick STL to store non-homogeneous function pointers.

EDIT: And Boost.Signals also looks promising, as mentioned above.

Share on other sites
Ey-Lord    225
hum, i just read the boost::signal doc, seems pretty nice !!
but whenever i try to include boost/singla.hpp i get a link error ... do i need to "build something" ? i never managed to build whatever what needed to be builed/linked with the boost lib .. ( if any1 got a full zip with all this builded ... just pm me ;) )

any ideas ?

Share on other sites
MaulingMonkey    1730
Quote:
 Original post by Ey-LordI just downloaded boost, and copy/paste the boost file in my include directory .I included boost/bind.hpp and boost/function.cpp

function.cpp or function .hpp?
Quote:
 I made a new var : std::vector< boost::function > vec ;and when i try to add something to this vecotr, i got an error :vec.push_back( boost::bind(glColor3ub, 0, 0, 0) );Errors are all in bind.hpp ... its wierd !

The errors are probably being created as the bind function template is being instantiated (read: used in your code).

Try using:

bind< void >( glColor3ub , 0 , 0 , 0 )

If that dosn't work, try copy & pasting this, which compiles using GCC:

#include <boost/bind.hpp>#include <boost/function.hpp>#include <GL/gl.h>#include <vector>int main(){        using namespace boost;        using namespace std;        vector< function< void ( void ) > > functions;        functions.push_back( bind( glColor3ub , 0 , 0 , 0 ) );}

If this does not compile, it would appear to be a 2K3 issue... prehaps due to the function being extern "C" void(*)(...) rather than extern "C++" void(*)(...) ? Err... right... to try that, try this:

#include <boost/bind.hpp>#include <boost/function.hpp>#include <GL/gl.h>#include <vector>void my_glColor3ub( GLubyte r , GLubyte g , GLubyte b ){    glColor3ub( r , g , b );}int main(){        using namespace boost;        using namespace std;        vector< function< void ( void ) > > functions;        functions.push_back( bind( my_glColor3ub , 0 , 0 , 0 ) );}

If this works, then allow me to detail the problem:

Normal C++ function pointers act like C function pointers. However, the standard specifices they're not the same. That means that technically this is a no no:

void (*cpp_function_pointer)( void ) = c_function;

You have two options: write a small wrapper function (see above), or use a C style function pointer (see bellow):

extern "C" void (*c_function_pointer)( void ) = c_function;

(not 100% sure if that's the right syntax). Seeing as I doubt boost has this extra definition, it may be failing to match against the correct template, and the automatic template deduction of things like return types thus failing as well.

Share on other sites
Ey-Lord    225
First of all -> thx :)
I just added <void> and it does compile !
I'm gonna try if it do what i want tought ;o)

and : typo mistake, function.Hpp :) sry

Hum, the <void> thing, is a cast of the return type , isnt it ?
if yes -> why do i have to cast ? the gl function already returns void, right ?
if no -> im lost :p

thx

edit: just a small edit before eating :)
If i change de function in my psuh_back , i get a bunch of error ( i took a function in my current class )
But with the gl , it works fine ( can i can call it when i want, no pb on this )

ex:
vec.push_back( boost::bind<void>(glColor3ub, 0, 0, 0) );		vec.push_back( boost::bind<void>(&cTexteDialogue::TraiterTexte, "lol") );

( cTexteDialogue is my current class )

Create an account

Register a new account