Passing Function?

Pages: 12
We all know that we can pass variables and values and everything else through functions. But is there a way to pass a function to a function?

Here's a scenario:
I've been developing my menu class lately and I've come to a point where I don't think this is possible. I want to be able to set it so that when someone selects one of my menu options, it will launch a function from there.

My idea of what the code would look like:
myMenu.AddOption("Here is my option text", MyFunction);

Now typically when we put a function call anywhere in our code, it gets run as soon as the compiler gets there, in this case, running before the user would get a chance to select my option.

Is there anyway to make this possible? Or do I need to show another example of what I mean?
Certainly. Even C had function pointers and in C++11 you use the more powerful std::function:

1
2
//accepts functions that return void and take no parameters:
void AddOption(std::string,std::function<void()> func) 
Why did I never learn about this??? This seems so helpful. Is there a link I can read up on this?

From the way your example looks, it looks like you're calling a void function. And then in my AddOption definition, how would I call my passed function? Just like a typical function call?
Just like a typical function call?

Yes.

The tutorial on this site has a short section on regular function pointers at the bottom:
http://www.cplusplus.com/doc/tutorial/pointers/
In that example, the function pointer is dereferenced explicitly, which is not necessary (although allowed).
It should have been written as follows:
return functocall(x,y);

The same example with std::function:
1
2
3
4
int operation (int x, int y, std::function<int(int,int)> func)
{
    return func(x,y);
}
This site needs to play catch up on C++11. cppreference has some reference pages on the subject:

http://en.cppreference.com/w/cpp/utility/functional


But really, it's very simple:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void func1()
{
  // a function that takes no parameters and does nothing
  cout << "in global func1" << endl;
}

class Example
{
public:
  int value;

  void memberfunc()
  {
    cout << "in memberfunc.  value=" << value << endl;
  }
};

void CallAFunction( std::function< void() > functocall )
{
  functocall();  // call it normally
}

int main()
{
  // call a global function
  CallAFunction( func1 );  // prints "in global func1"

  // call a member function (a little more complicated):
  Example e;
  e.value = 10;
  CallAFunction( std::bind( &Example::memberfunc, std::ref(e) );
    // prints "in memberfunc.  value=10"
}



You can also use bind() to tie together functions where the parameter list doesn't exactly match:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void f(int a, int b)
{
  cout << "a = " << a << ", b = " << b << endl;
}

void callit( std::function< void(int) > ptr )  // note our 'ptr' only takes 1 parameter
{
  ptr( 10 );  // passing '10' as the parameter
}

int main()
{
  callit( std::bind( f, std::placeholders::_1, 20 ) );  // prints "a = 10, b = 20"
}


As you can see, the function we give to callit only accepts one parameter. But we want to give it a function that has 2 parameters. So we use bind() to say "use whatever paramter callit provides as the 1st param, and use 20 as the 2nd param".
Sounds like I can really use this. I have a few more questions since I'm on my phone and can't actually try it, but let's say I want to call
myMenu.AddOption("Settings", settingsMenu.Play(1));

How would that work? Does it even work when using class functions?

Would I be able to implement a template for std::function as well? Let's say I want to do
settingsMenu.AddOption("Increase Difficulty", myGame.Difficulty ++)

Or would I have to make two seperate function calls?
This is what lambda functions are for:
settingsMenu.AddOption("Increase Difficulty", [&]() {myGame.Difficulty++;});

Same for settingsMenu.Play(1), although you could also use bind instead of a lambda function for that one.
Last edited on
myMenu.AddOption("Settings", settingsMenu.Play(1));


What you're doing there is calling the Play() function and passing the return value as the option you're adding. That won't work.

But... you can do what you are attempting here. And yes it works with class/member functions. Just bind it:

1
2
3
4
// assuming AddOption looks something like this:
//  void AddOption( string name, function<void()> functocall )

myMenu.AddOption( "Settings", bind( &YourMenuClass::Play, ref(settingsMenu), 1 ) );


The "gotcha" is that you are giving myMenu a reference to your settingsMenu object, so settingsMenu must remain in scope for as long as myMenu is hanging on to that reference.

Would I be able to implement a template for std::function as well? Let's say I want to do
settingsMenu.AddOption("Increase Difficulty", myGame.Difficulty ++)


I'm not sure I see what you mean by template, since you aren't using templates there.

However if you want a quickie function, that's what lambdas are for:

 
settingsMenu.AddOption("Increase Difficulty", [&] () { myGame.Difficulty++; } );


A lambda is effectively a short anonymous function. You can pass a pointer to that function as a std::function object, so your AddOption function can call it back.

More on lambdas here:
http://www.cprogramming.com/c++11/c++11-lambda-closures.html


EDIT: Dammit Athar, stop being a ninja
Last edited on
Ok, I can try and type this out a little better on another computer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Menu settingsMenu;

// Create an empty menu name myMenu
Menu myMenu;

// Add an option to call void Play() when selected
myMenu.AddOption("Play Game", std::function <int()> Play);
// Could I do this as well to keep it as a standard?
// myMenu.AddOption("Play Game", [&] () { Play });
// Or this since AddOption will already know it accepts:
// AddOption(std::string, std::function);
// myMenu.AddOption("Play Game", Play);

myMenu.AddOption("Display Another Menu", bind( &YourMenuClass::Play, ref(settingsMenu), 1);
// I'm trying to learn more about the bind function, but is it required only for a class call?

// Display "Thanks for playing" when selected
myMenu.AddOption("Exit", [] () { std::cout << "Thanks for playing"; });

// Run the menu
myMenu.Play();


Now that's a quick copy of what I think it should look like. My AddOption function for my Menu class should look something like:
1
2
3
Menu::AddOption(std::string optionString, std::function <void> optionFunction) {
...
}


Will that handle everything I've done so far?

And I asked about using a template simply because I'm not positive that every function that is added in there will be void, int, etc.
Would I need to add a separate definition for each possible call to it? I'm trying to make my menu class as versatile as possible, and this includes making it so that the class handles all of the extra coding.

You can take a look at my current Menu class here:
http://cplusplus.com/forum/beginner/73054/

Essentially, I want to remove all of the "extra" code from my main.cpp and let the class handle the switching dynamically. Is this possible? I know there would be a bunch of design changing within my menu, but it's something that would greatly improve it as well. Aside from the unusual code within the function calls and such, what are potential draw backs? Is this something that's possible that's not going to make my menu code enormous?

I appreciate the reading material and it's definitely going to be an interesting read, I've never heard of or seen anything like this stuff before and to be honest, it's a good bit over my head. I'll have to sit down and read it a few times to wrap my head around it.

Thank you guys so much.
Last edited on
Alright guys, this is what I've come up with so far. I just got home, wanted to make sure that my compiler was working correctly before I started a major overhaul. I'm getting a bunch of issues, but I believe they're all stemming from the std::function specifically. The error says function is not a member of std.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>

void FunctionToCall(std::function<void()> myFunction);
void CallFunction();

int main() {
    FunctionToCall(CallFunction);

    return 0;
}

void FunctionToCall(std::function<void()> myFunction) {
    myFunction();
}

void CallFunction() {
    std::cout << "Hello World!";
}


Is my syntax right so far? Is there maybe something that I messed up? Or is this my test that g++ isn't compatible with C++11 yet?
Test looks fine, but you need to #include <functional> (and compile with -std=c++0x or -std=c++11 if you don't do that already).
That one little line...UGH! And I am using -std=C++0x, it's default in the current nightly for C::B

That did fix it, so I'm good to go, atleast I believe. But before I stop bugging you guys, I just want to make sure I completely understand all of this.

my previous example is good for...only calling local functions, i guess that's what they're called. And in order to use a function from another class, I need to use std::bind correct? And now where do lambda's play in? Are they only used for inline calls? I mean I read up on them, but according to the last two things, lambda seems to only cover inlines...do lambdas work better if I just use them for all of the above? I'm kind of lost as to which one I should focus on mainly
On a side note, basically the reason I've been wanting to do this is so that when you select an option, I want the menu class to handle everything, as I've said before. I'm thinking I'm going to make an option class that has a name and a function, but I'm thinking about other ideas that can be implemented, such as on/off switches, values 1-10 that the user can increase or decrease, and whatever else that has been seen in option menus.

My other question is, what do you think is the best way to implement other options other than just functions? They seem to be easy.

I was thinking for like the on/off toggle, to allow the user to hit enter and turn the option on/off, but I'm not sure how to go about this. That's why I asked about the template. AddOption could accept (string, function) (string, bool) (string, int) but I am not sure if the template covers functions or not. That's why I asked earlier about them. I've also never used a template before, but am very interested in them, they seem extremely handy when having to write once and only once.
AddOption could accept (string, function) (string, bool) (string, int)


I might be misunderstanding, because I still don't see how templates would help you here.

If you want to have different kind of options behave differently, then I would probably just overload the AddOption function. But keep in mind you will need to group together all these options somehow so that they can all be triggered with a common interface.

For example... I assume your menu class has some kind of vector which contains the available options:

 
vector< Option > menuOptions;


So let's say the user selects option 2:

 
menuOptions[2].Perform();


This "Perform" function is your common interface. If you have different kinds of options that need to be performed differently, how can your menu class perform them? It all needs to be funneled through this kind of common interface.
I'm still trying to come up with the ideas myself, which is much harder than I had originally thought. The function calling is easy. I believe I may do an option class within the menu class that has friend variables to hold each possible choice. I honestly don't know much about overloading either. I see the term and I've been told I overloaded something before, but never knew how, why, or anything else.

I'm still trying to wrap my head around the std::function, std::bind, and lambda, but what would I need to learn about overloading? It sounds interesting =D

And please pardon my extreme excitement to learn, but I feel like a kid in a candy store right now, learning about all these great new things that weren't possible back when I first started programming. I'm always eager to learn more, and one day my brain is just going to quit, but until then, lets overload that. (I made a funny)
I'm still trying to come up with the ideas myself, which is much harder than I had originally thought


Designing is the hardest part of programming. Once you have the design, actually writing the code is easy.

I believe I may do an option class within the menu class that has friend variables to hold each possible choice.


Friends are a sign of a poor design. Menu and Option likely don't need to be friends.

I honestly don't know much about overloading either.

Overloading a function just means you have two different functions with the same name (but different parameter lists).

For example:

1
2
3
4
5
6
7
8
9
// two overloaded functions
void func( int bar );
void func( bool bar );

int main()
{
  func( 5 );  // calls the 'int' overload
  func( false );  // calls the 'bool' overload
}


And please pardon my extreme excitement to learn


Excitement to learn is a good thing! Hopefully we're not shoving too much in your face. It might be difficult to absorb all of this when there's so much of it coming out.



As for your design problem... you might want to consider polymorphism. It seems to be possibly the best solution here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class MenuOption
{
public:
  virtual ~MenuOption() { }

  virtual void  Perform() = 0;
};

class BoolMenuOption
{
public:
  virtual void Perform() { state = !state; }
private:
  bool  state;
};


class Menu
{
public:
  void AddOption( string name, Option* opt )
  {
    // .. add opt to your list ..
  }
};


//......

// you can add all sorts of different options, as long as they derive from MenuOption
//   each different kind of MenuOption will do something different when Perform is called:
myMenu.AddOption( "A bool option", new BoolMenuOption );
myMenu.AddOption( "An int option", new IntMenuOption );
//... 
Last edited on
Ok, I understand the overloading thing. I've done that a few times before. I believe it's the same when you have a function that has 4 parameters, but you don't need to pass any since you determine default values...I might be wrong on that one. But yes, I have used the different types before.

I have never done polymorphism, this is what's going to be the death of my mind it looks like. I might need to read up better to see how it works and how I can apply it to my design.

I said about the friend classes because I want Menu to be able to have access to all of the option class, but nothing else. Is there an alternative? Can I create the option class within the menu class?

One small step at a time, definitely. But between responding on here, I'm busy implementing everything I learned into my menu class and am also working on a sample project to test the things I want to try before adding it in. I'm still confused about using two different objects of the same class, I want to touch base on the bind thing again...

This was my original code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
int main() {
    // Disable Console Cursor
    VP_SetConsoleCursor(false);

    // Declare Main Menu
    Menu MainMenu("Tic-Tac-Toe", "-> ", " <-");
    MainMenu.AddOption("Single Player");
    MainMenu.AddOption("MultiPlayer");
    MainMenu.AddOption("Settings");
    MainMenu.AddOption("Exit");

    // Declare Multiplayer Menu
    Menu MultiMenu("Multiplayer", "-> ", " <-");
    MultiMenu.AddOption("Local Multiplayer");
    MultiMenu.AddOption("TCP/IP");
    MultiMenu.AddOption("Main Menu");

    // Declare Settings Menu
    Menu SettingsMenu("Settings", "-> ", " <-");
    SettingsMenu.AddOption("Difficulty");
    SettingsMenu.AddOption("Nickname");
    SettingsMenu.AddOption("Main Menu");

    // Handle Menus
    do {
        // Display MainMenu with previously used selection and return the new selection
        switch(MainMenu.Play(MainMenu.LastSelection())) {
        // Single Player
        case 1:
            // Play Single Player
            break;
        // Multiplayer
        case 2:
            // Handle Multiplayer Menu
            do {
                // Display MulriMwnu with previously used selection and return the new selection
                switch(MultiMenu.Play(1)) {
                // Local Multiplayer
                case 1:
                    break;
                // TCP/IP
                case 2:
                    break;
                }
            // Main Menu
            } while(MultiMenu.LastSelection() != MultiMenu.Size());
            break;
        // Settings
        case 3:
            // Handle Settings Menu
            do {
                // Display SettingsMenu with previously used selection and return the new selection
                switch(SettingsMenu.Play(1)) {
                // Difficulty
                case 1:
                    break;
                // Nickname
                case 2:
                    break;
                }
            // Main Menu
            } while(SettingsMenu.LastSelection() != SettingsMenu.Size());
            break;
        }
    // Exit
    } while(MainMenu.LastSelection() != MainMenu.Size());

    return 0;
}


Eventually, I want something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

    // Declare Multiplayer Menu
    Menu MultiMenu("Multiplayer", "-> ", " <-");
    MultiMenu.AddOption("Local Multiplayer", LocalPlay);
    MultiMenu.AddOption("TCP/IP", NetworkPlay);
    MultiMenu.AddOption("Main Menu");

    // Declare Settings Menu
    Menu SettingsMenu("Settings", "-> ", " <-");
    SettingsMenu.AddOption("Difficulty", /* Add Something Here */);
    SettingsMenu.AddOption("Nickname", /* Add Something Here */);
    SettingsMenu.AddOption("Main Menu");

    // Declare Main Menu
    Menu MainMenu("Tic-Tac-Toe", "-> ", " <-");
    MainMenu.AddOption("Single Player", Play);
    MainMenu.AddOption("MultiPlayer", MultiMenu.Play);
    MainMenu.AddOption("Settings" SettingsMenu.Play);
    MainMenu.AddOption("Exit");

    MainMenu.Play();


So far I've gotten how to call my global functions, but I haven't even attempted to work on the class functions. But as you can see, to run my previous menu properly, you have some work to do there. I want to make it so that I just "Play" one menu and it does all of the hard work, I have nothing else to worry about or any function calling, the menu class handles all of that.

I did mess around with the bind, and here is what I've done so far (ignore the vectors of the same thing, it was a test for my menus):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <functional>
#include <vector>
#include "..\lib\menu.h"

void FunctionToCall(std::function<void ()> myFunction);
void CallMe();

int main() {
   std::vector<std::function<void ()>> myFunctions;
   myFunctions.push_back(std::bind(FunctionToCall, CallMe));
   myFunctions.push_back(std::bind(FunctionToCall, CallMe));
   myFunctions.resize(3);
   myFunctions.push_back(std::bind(FunctionToCall, CallMe));
   for(int i = 0; i < myFunctions.size(); i ++)
      if(myFunctions[i])
         myFunctions[i]();

   return 0;
}

void FunctionToCall(std::function<void ()> myFunction) {
   if(myFunction)
      myFunction();
   else
      std::cout << "You didn't call a function";
}

void CallMe() {
   std::cout << "You Called Me!";
}


As you can see, I haven't implement passing arguments yet, but I do want to get there eventually.

I know this is a long winded post, and you're probably sick of seeing me at the top of the General Board, but I'm kinda excited, I'm not going to lie.

And I love learning, and implementing everything into something you, and others, use makes me feel 100 times better about learning. I have been posting about my updates on my menu class, but I feel the heads up on this is worth an update.

Thank you so much for entertaining me so far as well. You've brought multiple smiles to my face and they have pretty much stayed all night so far.
Alright guys, I'm back. I believe I've set up my menu correctly so far. I created a vector like so:
std::vector<std::function<int ()>> myMenuFunctions

And have set up my menus accordingly:
1
2
3
4
      void AddOption (std::string option = "", std::function<int ()> func) {
         vMenuOptions.push_back (option);
         vMenuFunctions.push_back (func);
      }


And I have used this in my main:
1
2
3
4
5
6
    // Declare Main Menu
    Menu MainMenu("Tic-Tac-Toe", "-> ", " <-");
    MainMenu.AddOption("Single Player");
    MainMenu.AddOption("MultiPlayer", [&] () {MultiMenu.Play;});
    MainMenu.AddOption("Settings", std::bind(&Menu::Play, std::ref(SettingsMenu)));
    MainMenu.AddOption("Exit");


I'm getting errors saying that:
C:\Programming\Menu_Example2\..\lib\menu2.h|115|error: default argument missing for parameter 2 of 'void Menu::AddOption(std::string, std::function<int()>)'|
C:\Programming\Menu_Example2\..\lib\menu2.h|124|error: default argument missing for parameter 3 of 'void Menu::SetOption(unsigned int, std::string, std::function<int()>)'|
C:\Programming\Menu_Example2\..\lib\menu2.h||In member function 'void Menu::AddOption(std::string)':|
C:\Programming\Menu_Example2\..\lib\menu2.h|111|error: no matching function for call to 'std::vector<std::function<int()> >::resize(std::vector<std::basic_string<char> >&)'|


I had to chop a lot of the stuff off. I wasn't sure if everything was related or not, but now I'm stuck.

@Disch
Do I need to overload my AddOption function to handle each possibility??? I wasn't quite expecting both of them to be wrong. The std::function seems to be the easiest and definitely the most pleasant to look at.

Am I implementing my class functions incorrectly to handle std::function, std::bind, and lambda?

Edit: Was able to fix it by changing the defaults, but I'm not sure it was the correct way:
1
2
3
4
      void AddOption (std::string option = "", std::function<int ()> func = "") {
         vMenuOptions.push_back (option);
         vMenuFunctions.push_back (func);
      }


I'm not getting errors from my original calls to AddOption(std::string); it says:
C:\Programming\Menu_Example2\main.cpp|14|error: call of overloaded 'AddOption(const char [18])' is ambiguous|

And:
C:\Programming\Menu_Example2\main.cpp|27|error: statement cannot resolve address of overloaded function|


I know what it's saying, but why did it break? Do I need to call all of my add options now as AddOption(std::string, ""); just to make it happy?
Last edited on
Update: This is the best I've been able to do. I've gotten member function calls working and the handling of the menu works as expected as well. The only issue I have is this...I have no idea how to make my options NOT require a function. After tinkering, this is what I got:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "..\lib\menu2.h"
#include "..\lib\header.h"

using namespace std;

int Display() { return 0; }

int main() {
    // Disable Console Cursor
    VP_SetConsoleCursor(false);

    // Declare Multiplayer Menu
    Menu MultiMenu("Multiplayer", "-> ", " <-");
    MultiMenu.AddOption("Local Multiplayer", Display);
    MultiMenu.AddOption("TCP/IP", Display);
    MultiMenu.AddOption("Main Menu", Display);

    // Declare Settings Menu
    Menu SettingsMenu("Settings", "-> ", " <-");
    SettingsMenu.AddOption("Difficulty", Display);
    SettingsMenu.AddOption("Nickname", Display);
    SettingsMenu.AddOption("Main Menu", Display);

    // Declare Main Menu
    Menu MainMenu("Tic-Tac-Toe", "-> ", " <-");
    MainMenu.AddOption("Single Player", Display);
    MainMenu.AddOption("MultiPlayer", std::bind(&Menu::Play, std::ref(MultiMenu), 1));
    MainMenu.AddOption("Settings", std::bind(&Menu::Play, std::ref(SettingsMenu), 1));
    /* std::bind( &Example::memberfunc, std::ref(e) */
    MainMenu.AddOption("Exit", Display);

    MainMenu.Play();

    return 0;
}


And AddOption looks like this:
1
2
3
4
5
6
7
8
9
10
11
      // Add new Option
      /*void AddOption (std::string option = "") {
         vMenuOptions.push_back (option);
         vMenuFunctions.resize (vMenuOptions.size());
      }*/

      // Add new Option with a function
      void AddOption (std::string option = "", std::function<int ()> func = "") {
         vMenuOptions.push_back (option);
         vMenuFunctions.push_back (func);
      }


I have absolutely no idea why it wouldn't let me leave my first AddOption in there, and why it required me to have defaults for my std::function types either. But now I can't figure out how to not pass a function to my AddOption class function.
Ok, I understand the overloading thing. I've done that a few times before. I believe it's the same when you have a function that has 4 parameters, but you don't need to pass any since you determine default values...I might be wrong on that one.


It's similar, but not quite the same thing.

Overloaded functions are multiple, unique functions that just happen to share the same name. They are only differentiated by the parameters they take.

Having default parameters is different because it calls only one singular function, but lets you omit some of the parameters in the call.


I have never done polymorphism, this is what's going to be the death of my mind it looks like. I might need to read up better to see how it works and how I can apply it to my design.


It's the single most important aspect of OOP. The idea is you have a general base class, and derive more specific types from it.

The classic example is to have a Dog base class, from which you would derive more specific types like Poodle, or GoldenLab. The inheritance forms an "is a" relationship (ie, deriving Poodle from Dog implies that a Poodle "is a" Dog). This means that anything you can do with a Dog, you can do with a Poodle.

But the real magic of polymorphism is virtual functions. Virtual functions allow you to call general functions in the base class, which have a specific implementation in the derived class. In English, this means that you can write different code for each different class, but call them all the same way, without knowing exactly what kind of class you have.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Dog
{
public:
  virtual void Speak() = 0;  // a virtual "Speak" function
};

class Poodle : public Dog  // A Poodle "is a" Dog
{
public:
  virtual void Speak() { cout << "yip yip"; }  // poodles are yappy dogs, so have it yip
};

class GoldenLab : public Dog // A lab "is a" Dog
{
public:
  virtual void Speak() { cout << "woof woof"; } // bigger dogs have bigger barks
};

//  ** THIS IS THE REAL MAGIC **
void DoSomethingWithADog( Dog* dog )
{
  // notice that the dog is just a pointer to a Dog, not a Poodle or a GoldenLab

  cout << "This is my dog, he is about to speak!" << endl;
  dog->Speak();  // this will magically call the Speak() of whatever derived class
    // the dog "actually" is.  So if "dog" points to a Poodle, this will yip,
    //  or if it points to a lab, this will woof.
}

int main()
{
  // some dogs
  Poodle myPoodle;
  GoldenLab  myLab;

  // since Poodles are Dogs, we can pass a pointer to a poodle as if it were a pointer to a dog:
  DoSomethingWithADog( &myPoodle );  // works.  When this function calls Speak, it will
    // call the Poodle's speak.

  // same with a lab:
  DoSomethingWithADog( &myLab );  // this time, when it calls Speak, it will call
    // GoldenLab's speak
}


This applies to your menu option in a bit less obvious way.

You could have a general 'MenuOption' class that has an "Action" function. You can then derive specific classes from MenuOption, each with their own Action function... and each Action function can do a different thing.



Continuing with your posts....

1
2
    MainMenu.AddOption("MultiPlayer", [&] () {MultiMenu.Play;});
    MainMenu.AddOption("Settings", std::bind(&Menu::Play, std::ref(SettingsMenu)));


Your Settings option here looks good. you're telling it to call SettingsMenu.Play(). But your MultiPlayer option is missing the function call parenthesis. You probably meant to do this:

MainMenu.AddOption("MultiPlayer", [&] () {MultiMenu.Play(); } );
Also... since your option is supposed to return an int, you probably should be returning something:
MainMenu.AddOption("MultiPlayer", [&] () {return MultiMenu.Play(); } );


------
void AddOption (std::string option = "", std::function<int ()> func)
Parameters that have a default value are optional. If you make one parameter optional, all others that come after it must also be optional. So if you give "option" a default value here, you must also give "func" one as well.

I don't recommend it. I'd say get rid of the default params here.

C:\Programming\Menu_Example2\..\lib\menu2.h|111|error: no matching function for call to 'std::vector<std::function<int()> >::resize(std::vector<std::basic_string<char> >&)'|

This suggests you are using resize incorrectly. Can't tell what you're doing wrong because you didn't show that particular line of code.



Do I need to overload my AddOption function to handle each possibility??? I wasn't quite expecting both of them to be wrong. The std::function seems to be the easiest and definitely the most pleasant to look at.


You only need to make AddOption overloads if you need to have multiple different types of objects that you are sending to the menu. Really, my answer to this question would be "no", because you should try to come up with a design that has a unified interface (ie: a common interface by which all menu options can be activated the same way).

Callbacks (function<void()>) are one way to do this. As is polymorphism. Personally I prefer polymorphism.


Edit: Was able to fix it by changing the defaults, but I'm not sure it was the correct way:
void AddOption (std::string option = "", std::function<int ()> func = "") {


That shouldn't work. You are assigning a string ("") to func. func is not a string, it's a function.

Get rid of the default parameters. They're just screwing you up. I'm willing to be that your ambiguous call errors are all because of to them.
Last edited on
Pages: 12