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() etc
Implementacja 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ń