Holas estimados ,
estaba jugando un poco con c++ para crear una clase que manejara menus de consola.
Hasta ahora tengo algo funcionando como esto:
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:
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
Conviértelo a void*.
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.
#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?
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 %.
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.