What I've come up with so far are two classes, one that makes and shows a console based menu and one that handles the actual options and actions mapped to those options. But I can't figure out a simple and elegant way to allow functions with different parameters and return types. Here's what I have so far
Code:
#include <iostream>
#include <cstdlib>
#include <string>
#include <list>
#include <map>

using namespace std;

// Create and display a console based menu
class ConsoleMenu {
public:
    ConsoleMenu(string omsg): msg(omsg){};
    void add(string opt) { options.push_back(opt); }
    ostream& display();
private:
    string       msg;
    list<string> options;
};

ostream& ConsoleMenu::display()
{
    list<string>::const_iterator it = options.begin();

    while (it != options.end())
        cout<< *it++ <<'\n';

    return cout<< msg <<flush;
}

// Map menu options to functions
class MenuOptions {
public:
    void add(int opt, void (*fn)()) { actions[opt] = fn; }
    bool getOpt();
    void run() { actions[option](); }
private:
    int                  option;
    map<int, void (*)()> actions;
};

bool MenuOptions::getOpt()
{
    if (cin>>option && actions.find(option) != actions.end())
        return true;
    
    if (!cin.good())
    {
        cin.clear();
        
        int ch;
        while ((ch = cin.get()) != '\n' && ch != EOF)
            ;
    }

    return false;
}

void a() { cout<<"\nOption 1\n"<<endl; }
void b() { cout<<"\nOption 2\n"<<endl; }
void c() { exit(0); }

int main()
{
    ConsoleMenu menu("Choose an option: ");
    MenuOptions mopt;

    menu.add("1) Option 1");
    menu.add("2) Option 2");
    menu.add("3) Quit");

    mopt.add(1, a);
    mopt.add(2, b);
    mopt.add(3, c);

    while (1)
    {
        menu.display();

        if (mopt.getOpt())
            mopt.run();
        else
            cerr<<"\nInvalid option\n"<<endl;
    }
}
What I can't figure out is how to have different types of functions for each call to run() without losing the really simple interface I have. Has anyone encountered a problem like this before? If so, what was your solution?