Zaawansowane CPP/Ćwiczenia 11: Funktory: Różnice pomiędzy wersjami
Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Nie podano opisu zmian |
Nie podano opisu zmian |
||
Linia 50: | Linia 50: | ||
g(3.14);h(3.14,0) | g(3.14);h(3.14,0) | ||
}} | }} | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Podpowiedź</span><div class="mw-collapsible-content" style="display:none"> | |||
Można zacząć od zaimplementowania pomocniczego adaptera | |||
<tt>call/tt>, który wywołuje funkcje dopasowując liczbę argumentów: | |||
int f(); | int f(); | ||
void g(double); | void g(double); | ||
void h(double,int); | void h(double,int);<br> | ||
call<double>(f)(x); /* woła f();*/ | |||
call<double>(g)(x); /* woła g();*/ | |||
call<double,double>(f)(x,y); /* woła f();*/ | |||
call<double,int>(g)(x,i); /* woła g(x);*/ | |||
call<double,int>(h)(x,i); /* woła h(x,i);*/ | |||
call< | Argumenty szablonu określają typy argumentów funktora zwracanego przez | ||
<tt>call<>()</tt>. | |||
</div></div> | |||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie</span><div class="mw-collapsible-content" style="display:none"> | |||
Nierekurencyjna funkcja przechodząca drzewo wgłąb może wyglądać następująco: | |||
std::deque<node *> nodes; | |||
nodes.push_back(_root);<br> | |||
while(!nodes.empty()) { | |||
node *nd <nowiki> =</nowiki> nodes.back(); | |||
nodes.pop_back();<br> | |||
if(node->right) nodes.push_back(node->right); | |||
if(node->left) nodes.push_back(node->left); | |||
} | |||
Iterator będzie wykonywał ten algorytm krok po kroku. W każdym kroku | |||
węzeł <tt>nd</tt> będzie wezłem wskazywanym przez ten iterator. | |||
Jako oznaczenie końca iteracji wykorzystamy iterator wskazujący na węzeł pusty. | |||
Definujemy klasę zagnieżdżoną wewnątrz <tt>binary_tree</tt>: | |||
class iterator { | |||
std::deque<node *> _nodes; | |||
node *_current;<br> | |||
iterator(node *ptr <nowiki> =</nowiki> 0):_current(ptr) { | |||
if(_current) { | |||
if(_current->right) | |||
_nodes.push_back(_current->right); | |||
if(_current->left) | |||
_nodes.push_back(_current->left); | |||
}<br> | |||
iterator &operator++() { | |||
_current<nowiki> =</nowiki> _nodes.back(); | |||
_nodes.pop_back();<br> | |||
if(_current) { | |||
if(_current->right) | |||
_nodes.push_back(_current->right); | |||
if(_current->left) | |||
_nodes.push_back(_current->left); | |||
} | |||
else | |||
_current<nowiki> =</nowiki> 0; | |||
} | |||
Żeby ta klasa zachowywała się jak wskaźnik dodajemy operatory: | |||
public: | |||
T &operator*() {return _ptr->_val;}; | |||
T *operator->() {return &(_ptr->_val);}; | |||
Potrzebny jest też operator porównania: | |||
bool operator<nowiki> =</nowiki> <nowiki> =</nowiki> (const trivial_iterator&lhs) const { | |||
return this->_ptr<nowiki> =</nowiki> <nowiki> =</nowiki> lhs._ptr; | |||
} | |||
bool operator!<nowiki> =</nowiki> (const trivial_iterator&lhs) const { | |||
return !operator<nowiki> =</nowiki> <nowiki> =</nowiki> (lhs); | |||
} | |||
Potrzebna jest jeszcze deklaracja: | |||
friend class binary_tree; | |||
żeby klasa <tt>binary_tree</tt> mogła korzystać z konstruktora | |||
<tt>iterator(node *ptr)</tt>. | |||
W klasie <tt>binary_tree</tt> definiujemy funkcje: | |||
iterator begin() {return iterator(_root);} | |||
iterator end(){return iterator(0);} | |||
</div></div> |
Wersja z 10:36, 25 wrz 2006
Ćwiczenie 1
Zaimplementuj adapter compose_f_gx_hy
realizujący złożenie dwuargumentowe .
Ćwiczenie 2
Korzystając z klasy functor_traits
zaimplementuj adpter bind1st
, który bedzie działał zarówno dla funktorów jedno-, jak i dwuargumentowych.
Ćwiczenie 3
Zaimplementuj funktor implementujący, składanie funkcji poprzez wykonywanie ich po kolei np.:
macro(f1,f2)(x)
powinno wykonać
f1(x);f2(x);
Wartości zwracane przez te funkcje są ignorowane. Funkcja macro powinna zwracać funktor odpowiedniego typu (posiadający odpowiednie typy stowarzyszone) tak, aby możliwe było dalsze składanie np.:
macro(macro(f1,f2),f3)(x)
powinno wywołać:
f1(x);f2(x);f3(x);
Ćwiczenie 4
Zmodyfikuj powyższy szablon tak aby można było mieszać funkcje o różnej liczbie agrgumentów np.:
int f(); void g(double); void h(double,int);
macro(f,g)(x);
powinno wywołać
f();g(x)}
a
macro(g,h)(3.14,0);
powinno wywołać
g(3.14);h(3.14,0)
Podpowiedź
Rozwiązanie