Puntero a funcion como argumento

Iniciado por _Enko, 9 Enero 2015, 22:10 PM

0 Miembros y 1 Visitante están viendo este tema.

_Enko

Holas estimados ,
estaba jugando un poco con c++ para crear una clase que manejara menus de consola.
Hasta ahora tengo algo funcionando como esto:
Código (cpp) [Seleccionar]

void proc1(void){
    std::cout << "proc1" << std::endl;
}
void proc1a(void){
    std::cout << "proc1a" << std::endl;
}
void proc1b(void){
    std::cout << "proc1b" << std::endl;
}
void proc2(void){
    std::cout << "proc 2" << std::endl;
}

void proc3a(void){
    std::cout << "proc 3a" << std::endl;
}
void proc3b(void){
    std::cout << "proc 3b" << std::endl;
}
void proc3c(void){
    std::cout << "proc 3c" << std::endl;
}


   
int main(int argc, char* argv[]){
    CMenu menu;
    menu.AddMenu("OPCION 1", proc1);
    menu.AddSubMenu("OPCION1A", proc1a, 1); //submenu de la opcion 1
    menu.AddSubMenu("OPCION1B", proc1b, 1);
    menu.AddMenu("OPCION 2", proc2);
    menu.AddMenu("OPCION 3", NULL); //opcion 3 separador, no tendria funcion
    menu.AddSubMenu("OPCION3A",  proc3a, 3); //submenu de la opcion 3
    menu.AddSubMenu("OPCION3B", proc3b, 3);
    menu.AddSubMenu("OPCION3C", proc3c, 3);
    menu.PrintMenu();
    menu.DoMenu();
    return 0;
}


El resultado es algo asi:
Citar
1: OPCION 1
   11: OPCION1A
   12: OPCION1B
2: OPCION 2
3: OPCION 3
   31: OPCION3A
   32: OPCION3B
   33: OPCION3C
0: SALIR
Eliga una Opcion:

Por ejemplo si se elige la opcion 11, se llamará a proc1a(), y esto se repite hasta que se elija salir.

El problema es, el puntero a funcion como parametro lo tengo defenido asi:
Código (cpp) [Seleccionar]

typedef void(*callback_proc_)(void);
inline void CMenu::AddMenu(const char* cap, callback_proc_ proc){


Con esta estructura, estoy forzando que el procedimiento que esta asociado al item del menu es "void name(void)"

Como se podría hacer para poder pasar como parametro a AddMenu() una funcion con numero y tipo de parametros desconocido?

Saludos Y gracias

ivancea96

Conviértelo a void*.

_Enko

Pero si lo convierto a void* el puntero a funcion tendria un argumento un puntero a void. Y lo que en realidad creo que necesito es tratar de pasarle como parametro una cantidad de parametros desconocida de tipo desconocido.

Código (cpp) [Seleccionar]

#include <vector>
#include <string>
#include <iostream>


typedef void(*callback_proc_)(void);
class CMenu;


class MenuItem{
    public:
        MenuItem(const char* cap, callback_proc_ proc):caption_(cap),proc_(proc){}
        ~MenuItem(){
            submenu_.clear();
        }
        friend class CMenu;
    private:
        callback_proc_ proc_;
        std::string caption_;
        std::vector<MenuItem> submenu_;
};

class CMenu{
public:
    inline void AddMenu(const char* cap, callback_proc_ proc);
    inline void AddSubMenu(const char* cap, callback_proc_ proc, int parent);
    inline void PrintMenu();
    inline void DoMenu();
    CMenu();
    ~CMenu();
   
private:   
     std::vector<MenuItem> menu_;
};

CMenu::CMenu(){
    menu_.push_back(MenuItem("SALIR", NULL));

}

CMenu::~CMenu(){
    for(int i = 1; i < menu_.size(); ++i){
        menu_[i].submenu_.clear();
    }
    menu_.clear();
}

inline void CMenu::AddMenu(const char* cap, callback_proc_ proc){
    menu_.push_back(MenuItem(cap, proc));
     
}
inline void CMenu::AddSubMenu(const char* cap, callback_proc_ proc, int parent){
    if(parent > menu_.size())
        throw("Indice del menu mayor que lista del menu");
    else
        menu_[parent].submenu_.push_back(MenuItem(cap, proc));
}

inline void CMenu::PrintMenu(){
    for(int i = 1; i < menu_.size(); ++i){
        std::cout << i << ": " << menu_[i].caption_ << "\n";
        for(int j = 0; j < menu_[i].submenu_.size(); ++j){
            std::cout << "   " << i * 10 + j + 1 << ": " <<  menu_[i].submenu_[j].caption_ << "\n";
        }
    }   
    std::cout << 0 << ": " << menu_[0].caption_<< "\n";
}

inline void CMenu::DoMenu(){
    int option = 0;
    int mainsize = menu_.size()-1;
    int msize = mainsize * 10 + menu_[mainsize].submenu_.size()+1;
    do{
        while ((std::cout << "Eliga una Opcion: ") && (!(std::cin >> option) || option < 0 || option > menu_.size()*10)) {
            std::cout << "Opcion Invalida! ";
            std::cin.clear();
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        }
       
        int imenu = option / 10;
        int isubm = option % 10;
        if(option < 10 && option > 0 && option < menu_.size()){
            if(menu_[option].proc_)
                menu_[option].proc_();
        } else if(option >=11 && isubm != 0 && imenu < menu_.size()){
            if(isubm <= menu_[imenu].submenu_.size())
                if(menu_[imenu].submenu_[isubm-1].proc_)
                    menu_[imenu].submenu_[isubm-1].proc_();
        } else {
            std::cout << "Opcion Invalida \n";
        }
    }while(option != 0);
   
 


teniendo  void proc(void) podria ahora hacer
Menu.AddMenu(proc);

Pero lo que estoy tratando de hacer es algo como esto:

int proc1(int x, int y);
char* proc2(const char * strCh);
Menu.AddMenu(proc1); //tipo incompatible
Menu.AddMenu(proc2);

Ba, en realidad estoy pensando que tengo que guardar el tipo y la cantidad de argumentos algo asi como hace printf?

ivancea96

#3
Si quieres una función con indeterminado número de argumentos: void func(int n, ...){}
Los argumentos son contiguos en memoria a la primera variable.
Obviamente, necesitas saber tipo y número de argumentos. Printf lo sabe buscando en la cadena los %.

Yoel Alejandro

Sólo como un comentario, que me parece muy interesante el tema, una manera muy práctica de manejar menús.

Y por supuesto, la sugerencia de ivancea es la apropiada  ;D para el problema planteado, es lo que se hace para manejar funciones con número variable de argumentos.
Saludos, Yoel.
P.D..-   Para mayores dudas, puedes enviarme un mensaje personal (M.P.)