Sign in to follow this  

stl stack fun

This topic is 4096 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm creating an application that runs as a stack: exit->menu->game. every part of a stack is a separate function. since STL stack cannot use function pointers, i wrap it like that:
struct StateStruct
{
   typedef void (*StatePointer)();
};

It run fine when the Exit(), Menu() and Game() functions were global, but I decided to try to change it to oop (and here came the uglies) I have class App, containing basically whole my program,
int main(int argc, char *argv[])
{
App *MyDemo = new App;
MyDemo->MainLoop();
delete MyDemo;
return 0;
}

void App::MainLoop() 
{
while (!stateStack.empty())
{
stateStack.top().StatePointer();
}
}


I've created a method Exit() of the App
void App::Exit() 
{
cout << "I am exiting game." << endl;
stateStack.pop();
}

and now in App::Init(), I try to use
StateStruct state;
state.StatePointer = Exit; // <-- DevCPP throws out error here
// state.StatePointer =&App::Exit; gives same error as the line above
stateStack.push(state);


the error is "invalid use of `StateStruct::StatePointer'" oh yeah,
stack<StateStruct> stateStack; // application's state stack

is a private member variable of class App. I _really_ have no idea what to do now. Any help will be appreciated.

Share this post


Link to post
Share on other sites
Quote:
Original post by EliteWarriorManTis
since STL stack cannot use function pointers, i wrap it like that:


Says who?

#include <iostream>
#include <stack>

void foo() { std::cout << "hi" << std::endl; }

int main()
{
std::stack<void (*)()> s;
s.push(&foo);
s.top()();
s.pop();
}




Quote:
the error is "invalid use of `StateStruct::StatePointer'"


A pointer to a (non-static) member function is not the same thing as a pointer to a non-member function. You cannot use one where the other is expected.

Furthermore (and that's the error you're getting), StateStruct::StatePointer is a type not a variable (see that typedef keyword), so trying to assign it a value is meaningless.

Share this post


Link to post
Share on other sites
Maybe this is just an intellectual exercise for you, in which case I'll shut up. But if you're trying to write practical code...well, you're using C++ as if it were C or ML. Object-oriented languages should be passing around objects, not functions. Make some State class with a virtual method you can override, then derive your Exit, Menu, and Game classes from that base. The syntax is much less ugly.

Share this post


Link to post
Share on other sites
Quote:
Original post by drakostar
Object-oriented languages should be passing around objects, not functions. Make some State class with a virtual method you can override, then derive your Exit, Menu, and Game classes from that base.


You can consider a function pointer as an object that only implements the function call operator. A virtual function call is more or less the same thing as using a function pointer anyway...

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by drakostar
Maybe this is just an intellectual exercise for you, in which case I'll shut up. But if you're trying to write practical code...well, you're using C++ as if it were C or ML. Object-oriented languages should be passing around objects, not functions. Make some State class with a virtual method you can override, then derive your Exit, Menu, and Game classes from that base. The syntax is much less ugly.
You gave the wrong reasons. A good reason to use objects in C++ is that they can contain state, whereas C++'s functions can't (no closures). But that of course doesn't apply if you're 100% sure you don't need state. Using function pointers isn't really that ugly, especially if you use typedef for the function pointer type.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
And by "state" I also mean non-mutable state like a parameter to a function that is fixed on the object creation site. Such state is very often useful..

Share this post


Link to post
Share on other sites
Thanks for all the replies. No, this is not a intellectual exercize, but like I stated: I wrote that I'm changing this from C-like functions to OOP, and I have problems with it, cause quite frankly I don't have that much experience with C++ specific solutions. Can anybody give me pseudocode/code how it would look with state class? I'd like to try that approach, but I've no idea where to start.

TIA

Share this post


Link to post
Share on other sites
Quote:
Original post by EliteWarriorManTis
Thanks for all the replies. No, this is not a intellectual exercize, but like I stated: I wrote that I'm changing this from C-like functions to OOP, and I have problems with it, cause quite frankly I don't have that much experience with C++ specific solutions. Can anybody give me pseudocode/code how it would look with state class? I'd like to try that approach, but I've no idea where to start.


class Function
{
public:
virtual void execute() const = 0;
};

class ExitFunction: public Function
{
public:
ExitFunction(int status = 0)
: m_status(status)
{ }

void execute() const
{ exit(m_status); }

private:
int m_status;
};

typedef std::stack<Function*> StateStack;

int main(int, char*[])
{
StateStack stateStack;
stateStack.push(new ExitFunction(-1));
stateStack.top()->execute();
}

Share this post


Link to post
Share on other sites
This is fine and all, but I still don't know how to insert this stack into my class App so that the functions like ExitFunction can access other members of the class, and be stacked at the same time. Note that I will have to use class MainLoopFunction (or something along the lines), and it'll have to have access to all the application stuff.

newb, eh?

Share this post


Link to post
Share on other sites
Quote:
Original post by EliteWarriorManTis
This is fine and all, but I still don't know how to insert this stack into my class App so that the functions like ExitFunction can access other members of the class, and be stacked at the same time. Note that I will have to use class MainLoopFunction (or something along the lines), and it'll have to have access to all the application stuff.


One of the hallmarks of poor object-oriented design is to have classes represent functions rather than things. An "Application" is probably a good choice for a class. A MainLoopFunction is probably not. It might, however, be a good candidate for a member function of an Application.

That said, it sounds like what you might want to do is either have the Application object be globally accessible from you stacked commands, or else pass a reference to the application to functions of your commands that need to ask the application object to do something.

SO, the App would have_a command stack, and commands would ask the application to perform some functions.

Since there is generally a single application object per, uh, application, many frameworks provide a global pointer to the application object.

Is this getting close to addressing your question?

Share this post


Link to post
Share on other sites
So, if I'd create the stack in main(), out of App, and just want it to run its respective functions like App.Exit(), App.MainLoop(), and App.Menu(), how do I do it? I hit recursiveness wall. I'm sure there's some way to do that, but I've no idea how. :S

Share this post


Link to post
Share on other sites
I havn't had a chance to fully grok what the remaining problem is, so I'm instead going to attack the original problem from the angle I'd take.

It involves using the Boost C++ Libraries, a wonderful toolset that belongs in every C++ programmer's environment in my opinion.

Part of the problem, which I gather has already been touched on, is that member functions don't behave exactly like static functions - they're not interchangable. Part of the boost library helps solve exactly this problem, and is the route I'm going to take.

#include <boost/function.hpp>
typedef boost::function< void ( void ) > StateFunction;


Okay, this is pretty simple - we typedef StateFunction to a boost::function that has a signature of "void ( void )" (returns nothing, takes no arguments). Same basic deal as the function pointer typedef.

We can have these directly in the stack:

#include <boost/bind.hpp>
#include <stack> //not sure this is the exact header :S
class Application {
std::stack< StateFunction > stateStack;
public:
Application();
void MainLoop();
void Exit();

private: //states
void Menu();
void Game();
};

Application::Application() {
stateStack.push( boost::bind( & Application::Menu , this ) );
stateStack.push( boost::bind( & Application::Game , this ) );
}

void Application::MainLoop() {
while ( ! stateStack.empty() ) {
stateStack.top()();
//spread out into two steps:
// const StateFunction & function = stateStack.top();
// function();
}
}

...


boost::bind is a tool that lets us "bind" arguments that will always be used when calling this function. We used it above so that we didn't have to have an explicit "this" parameter in our boost::function and pass it every time - instead, it will always be the same as the Application they were constructed in.

Now, all these member functions still have their "this" data, so no recursion problems (if this is what you were refering to later on):

void Application::Exit() {
while ( ! stateStack.empty() ) stateStack.pop();
}

void Application::Menu() {
...
if ( KeyDown( ESC ) ) Exit();
...
}


Hope this helps.

Share this post


Link to post
Share on other sites
Quote:
Original post by Bregma

class Function
{
public:
virtual void execute() const = 0;
};


In C++, we normally spell "execute()" as "operator()()". :)

Quote:
Original post by EliteWarriorManTis
So, if I'd create the stack in main(), out of App, and just want it to run its respective functions like App.Exit(), App.MainLoop(), and App.Menu(), how do I do it? I hit recursiveness wall. I'm sure there's some way to do that, but I've no idea how. :S


I can't understand that.

What is 'App'?

You say "run its respective functions" in a context that sounds like "its" refers to "the stack created in main()", but then say "App.whatever".

The idea is to have the stack be a *member of* some other object.

As for invoking functions that are contained on the stack, you were already given an example. All you need to do is get at the stack.

Looking back at the original code that you posted... what the REAL problem is, is this:


struct StateStruct
{
typedef void (*StatePointer)();
};

void App::Exit()
{
cout << "I am exiting game." << endl;
stateStack.pop();
}

StateStruct state;
state.StatePointer = Exit; // <-- DevCPP throws out error here


The type of 'Exit' IS NOT void(*)(). It is void(App::*)(). It is a pointer to a member function, which is not really a pointer in the traditional sense. Which is why you are in a world of pain. The brief summary is: How do you expect to store the concept of "App::Exit()" somewhere and then invoke it as if it were a plain function, when it's a member function? Hint: which App does it get invoked on? Ok, how does the *compiler* know that?

With functors, you can eliminate the problem by having the object store a pointer back to the App instance, and then invoking the member function on that instance from the functor.

Example:


#include <iostream>
#include <stack>

struct Function {
virtual void operator()() const = 0;
};

class Exiter: public Function {
App* app;
public:
Exiter(App* app): app(app) {}

void operator()() const { app->Exit(); }
};

class App() {
std::stack<Function*> stateStack;
void cleanup() {
// we probably should get rid of *all* states, yeah?
while (!stateStack.empty()) {
delete stateStack.top();
stateStack.pop();
}
}

public:
// DO NOT write a member function like App::Init(). Use constructors to
// construct things. Notice your original example failed to call Init().
// With a constructor, it is impossible to make that error.
App() { stateStack.push(new Exiter(this)); }
~App() { cleanup(); }
// Because we make sure of cleaning up in the destructor (RAII), we don't
// really need to do it in Exit(); we could instead set a flag that is
// checked in MainLoop(). But this way is pretty straightforward...

void MainLoop() {
while (!stateStack.empty()) {
// Grab a pointer to a function-object, dereference to get the function-
// object, and call it. The Exiter's operator() will dereference its
// App pointer (getting back this object!), and invoke the Exit() of that
// App instance (the current one, in our example, because we only made
// one). But now we have the flexibility e.g. to make several Apps, and
// have one of them tell another to Exit() via its states.
// Of course, maybe we don't *want* that, which is exactly why you got
// some advice not to make an App class :P
(*stateStack.top())();
}
}

void Exit() {
std::cout << "I am exiting game." << std::endl;
cleanup();
}
};

// By the way, there is absolutely no reason to allocate App dynamically.
int main(int argc, char *argv[]) {
App().MainLoop();
}

Share this post


Link to post
Share on other sites

This topic is 4096 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this