Takto sa strasia zaciatocnici :
#include <iostream>
#include <functional>
#include <string>
#include <map>
#include <memory>
#include <tuple>
template <class Key, class Value>
struct MenuItemBase{
const Key key;
Value value;
template <class Ostream>
friend Ostream& operator<<(Ostream& out, const MenuItemBase& x){
return out << x.key << ") " << x.value << std::endl;
}
virtual bool operator()()=0;
template <class K, class V>MenuItemBase(K&& key, V&& value)
:key(std::forward<K>(key)), value(std::forward<K>(value)){}
};
template <class Key, class Value, class Action>
struct MenuItem final : MenuItemBase<Key, Value> {
private:
using base = MenuItemBase<Key, Value>;
Action action;
public:
template <class K, class V>MenuItem(K&& key, V&& value, Action action = Action())
:base(std::forward<K>(key), std::forward<K>(value)), action(action){}
bool operator()()override{return action();};
};
template <int N, class Key, class Value, class... Items>
struct MenuItemGet;
template <class Key, class Value, class... Items>
struct Menu final : MenuItemBase<Key, Value>{
template <int N, class K, class V, class... Is>
friend class MenuItemGet;
protected:
using base = MenuItemBase<Key, Value>;
std::tuple<Items...> items;
std::map<Key, base*> map;
void reg_items(){MenuItemGet<static_cast<int>(sizeof...(Items))-1, Key, Value, Items...>::reg(*this);}
public:
template <class K, class V, class... Is>Menu(K&& key, V&& value, Is&&... items)
:base(std::forward<K>(key), std::forward<V>(value)), items(std::forward<Is>(items)...){}
Menu(Menu&& menu)
:base(std::move(menu.key), std::move(menu.value)), items(std::move(menu.items)){}
bool operator()()override{
bool cont = true;
while (cont) {
std::cout << "\n\nMenu: " << base::key << "\n";
MenuItemGet<static_cast<int>(sizeof...(Items))-1, Key, Value, Items...>::show(std::cout, *this);
std::cout << "Zadejte volbu: ";
Key in;
std::cin >> in;
if(map.size() != sizeof...(Items))reg_items();
auto item = map.find(in);
if (item != map.end()) {
std::cout << "Nalezeno, spoustim\n";
cont = item->second->operator()();
}
}
return true;
}
};
template <int N, class Key, class Value, class... Items>
struct MenuItemGet{
static void reg(Menu<Key, Value, Items...>& menu){
menu.map[std::get<N>(menu.items).key] = &std::get<N>(menu.items); //menu.reg_item<N>();
MenuItemGet<N-1, Key, Value, Items...>::reg(menu);
}
static void reg(MenuItemBase<Key, Value>& item){}
template<class Ostream>
static void show(Ostream& out, Menu<Key, Value, Items...>& menu){
out << std::get<sizeof...(Items) - N - 1>(menu.items);
MenuItemGet<N-1, Key, Value, Items...>::show(out, menu);
}
};
template <class Key, class Value, class... Items>
struct MenuItemGet<-1, Key, Value, Items...>{
static void reg(Menu<Key, Value, Items...>& menu){}
static void reg(MenuItemBase<Key, Value>& item){}
template<class Ostream>
static void show(Ostream& out, Menu<Key, Value, Items...>& menu){}
};
template <class Key, class Value, class... Items>
decltype(auto) make_menu(Key&& key, Value&& value, Items&&... items){
return Menu<Key, Value, Items...>{std::forward<Key>(key), std::forward<Value>(value), std::forward<Items>(items)...};
}
template <class Key, class Value, class Action>
decltype(auto) make_item(Key&& key, Value&& value, Action action){
return MenuItem<Key, Value, Action>{std::forward<Key>(key), std::forward<Value>(value), action};
}
bool akce(int m, int n, bool opakovat) {
std::cout << "provadim akci "<< m << "/" << n << "\n";
return opakovat;
}
int main(){
using std::bind;
using std::string;
auto menu = make_menu<string, string>("Hlavni menu", "-",
make_item<string, string>("1", "Akce 1", bind(akce,0,0,true)),
make_item<string, string>("2", "Akce 2", bind(akce,0,1,true)),
make_item<string, string>("3", "Akce 3", bind(akce,0,2,true)),
make_menu<string, string>("4", "Submenu 1",
make_item<string, string>("1", "Podakce 1", bind(akce,1,0,true)),
make_item<string, string>("2", "Podakce 2", bind(akce,1,1,true)),
make_item<string, string>("3", "Podakce 3", bind(akce,1,2,false)) // podakce 3 a navrat do predchoziho menu
),
make_item<string, string>("5", "Konec", bind(akce,0,5,false))
);
menu();
return 0;
}