Aliases aliasList; aliasList.add_for("number") * "one" * "two" * "three"; aliasList.add_for("moo") - "foo" - "bar" - "jaj"; aliasList.add_for("no_alias"); // identity std::cout << "three stands for " << aliasList["three"] << '\n';
List list; list.prons_and_cons_for("headphones X") + "price" + "quality" + "bass" - "too short cable" - "no volume control"; list.print_info_about("headphones X"); // or list.get_cons() etcImplementacja polega na rozbiciu na dwie klasy.
Pierwsza, najważniejsza klasa polega na tym, że akumuluje argumenty (albo w moim przypadku - posiada referencje do kontenera drugiej klasy) w zadany sposób poprzez przeładowanie operatorów zwracających referencję - tak jak przeładowuje się zwykle operatory ">>" oraz "<<", przy czym trzeba również pamiętać o priorytetach i kierunku łączenia.
Druga klasa (Aliases, List w przykładach) zajmuje się tworzeniem pierwszej klasy i zawiera kontenery i właściwą logikę.
Jeśli nie jest to jeszcze jasne, to wystarczy spojrzeć na kod (drafty):
Tak to wygląda w pierwszym przypadku:
class AliasFor { public: AliasFor(const string &name, AliasList &target) : m_target(target), m_name(name) { m_target[name] = name; // just add identity } AliasFor& operator-(const char* alias) { m_target[alias] = m_name; return *this; } /// you can use each of this operators in your "list" instead of "-". AliasFor& operator*(const char* alias) { return (*this) - alias; } AliasFor& operator+(const char* alias) { return (*this) - alias; } AliasFor& operator&(const char* alias) { return (*this) - alias; } AliasFor& operator<<(const char* alias) { return (*this) - alias; } private: map<string, string>& m_target; const string& m_name; }; class Aliases { public: // resolve alias or just return argument (to change if needed) std::string operator[](const string& alias){ AliasList::iterator it = aliases.find(alias); if (it == aliases.end()) return alias; return it->second; } // creating new temporary object which holds reference to container // and name to assign aliases with AliasFor add_for(const string& name) { return AliasFor(name, aliases); } private: AliasList aliases; };Przykład 2 jest troszkę bardziej skomplikowany - nie mniej główne założenia są takie same tylko jest trochę bardziej uogólnione:
template <typename T, typename TT> class PronsAndCons { public: typedef std::pair<std::set<TT>, std::set<TT> > TPronsAndCons; typedef std::map<T, TPronsAndCons> TThings; class ListPronsAndCons { public: friend class PronsAndCons; ListPronsAndCons& operator-(const TT & con) { tab.first.insert(con); return *this; } ListPronsAndCons& operator+(const TT & pron) { tab.second.insert(pron); return *this; } private: ListPronsAndCons(TPronsAndCons& p) : tab(p) {} TPronsAndCons& tab; }; ListPronsAndCons prons_and_cons_for(T what) { thing[what] = TPronsAndCons(); return ListPronsAndCons(thing[what]); } void print_info_about(const std::string &what) { TPronsAndCons& tmp = thing[what]; std::set<TT>::iterator it; std::cout << "Let's talk about " << what; std::cout << "\nProns are:"; for (it = tmp.second.begin(); it != tmp.second.end(); ++it){ std::cout << "\n\t+ " << *it; } std::cout << "\nCons are:"; for (it = tmp.first.begin(); it != tmp.first.end(); ++it){ std::cout << "\n\t- " << *it; } } private: TThings thing; }; typedef PronsAndCons<std::string, std::string> ThingList;Oczywiście można to rozbudować i dodając nowe typy można by napisać taką funkcjonalność:
Monster monster("joe"); monster.look() + head("one eye head") + torso("lion") + arms("with claws") + legs("frog"); monster.resistance() + fire(10) - frost(20); monster.equip() + coins(100) + sword("of destiny") + thing("monster eye");Czy jest to sensowne? Z pewnością nie ;) Ale można się pobawić, zobaczyć i zapomnieć :)
Dobree :)
OdpowiedzUsuńYou're a sick man rAum :P poważnie, czytam i nie wierzę :P
OdpowiedzUsuń