Zaawansowane CPP/Ćwiczenia 12: Używanie funktorów: Różnice pomiędzy wersjami
Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania(Nie pokazano 13 wersji utworzonych przez 2 użytkowników) | |||
Linia 1: | Linia 1: | ||
− | + | {{cwiczenie|1|| | |
+ | |||
Napisz algorytm <code><nowiki>for_each</nowiki></code> który działałby na dwu zakresach. | Napisz algorytm <code><nowiki>for_each</nowiki></code> który działałby na dwu zakresach. | ||
Linia 8: | Linia 9: | ||
InputIterator1 last1, | InputIterator1 last1, | ||
InputIterator2 first2, | InputIterator2 first2, | ||
− | BinaryFunction op); | + | BinaryFunction op);</nowiki> |
− | </nowiki> | ||
Algorytm ma działać tak jak standardowy <code><nowiki>for_each</nowiki></code>, tyle że funkcja | Algorytm ma działać tak jak standardowy <code><nowiki>for_each</nowiki></code>, tyle że funkcja | ||
Linia 17: | Linia 17: | ||
op(*(first1+1),*(first2+1); | op(*(first1+1),*(first2+1); | ||
...</nowiki> | ...</nowiki> | ||
+ | }} | ||
+ | |||
+ | <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"> | ||
+ | To rozwiązanie nie wymaga chyba komentarza. | ||
+ | |||
+ | template<typename InputIterator1, | ||
+ | typename InputIterator2, | ||
+ | typename BinaryFunction > | ||
+ | BinaryFunction for_each(InputIterator1 first1,InputIterator1 last1, | ||
+ | InputIterator2 first2, | ||
+ | BinaryFunction op) {<br> | ||
+ | for(;first1!<nowiki> =</nowiki> last1;++first1,++first2) | ||
+ | op(*first1,*first2);<br> | ||
+ | return op; | ||
+ | } | ||
+ | |||
+ | Kod znajduje się w pliku [[media:For_each.h | for_each.h]]. | ||
+ | </div></div> | ||
− | + | {{cwiczenie|2|| | |
− | |||
− | |||
− | |||
− | |||
− | + | Zaimplementuj opisany na wykładzie adapter, który opakowuje funkcję lub funktor, ignorując zwracaną przez nie wartość,, i zwracający zamiast niej jakąś wartość wybranego typu. Np.: | |
− | Zaimplementuj opisany w wykładzie iterator, który działa podaną | + | |
+ | double f(int); | ||
+ | adapt(f,7)(0); | ||
+ | |||
+ | wywołuje <tt>f(0)</tt> i zwraca <tt>7</tt>. | ||
+ | |||
+ | double f(int); | ||
+ | adapt(f)(0); | ||
+ | |||
+ | wywołuje <tt>f(0)</tt> i nie zwraca żadnej wartości. | ||
+ | }} | ||
+ | |||
+ | <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"> | ||
+ | template<typename Function , typename Result > class adapt_t: | ||
+ | public functor_traits<Function>::f_type { | ||
+ | typedef typename functor_traits<Function>::arg1_type arg1_type; | ||
+ | typedef typename functor_traits<Function>::arg2_type arg2_type; | ||
+ | Function _f; | ||
+ | Result _val; | ||
+ | public: | ||
+ | adapt_t(Function f,Result val):_f(f),_val(val) {}; | ||
+ | typedef Result result_type;<br> | ||
+ | result_type operator()() {_f();return result_type(_val);}; | ||
+ | result_type operator()(arg1_type a1) {_f(a1);return result_type(_val);}; | ||
+ | result_type operator()(arg1_type a1,arg2_type a2) {_f(a1,a2);return | ||
+ | result_type(_val);}; | ||
+ | }; | ||
+ | |||
+ | Do tego dochodzi jeszcze specjalizacja dla <tt>Result <nowiki> =</nowiki> void</tt> i funkcje: | ||
+ | |||
+ | template<typename R,typename F> adapt_t<F,R> | ||
+ | adapt(F f,R val) {return adapt_t<F,R>(f,val);} | ||
+ | template<typename F> adapt_t<F,void> | ||
+ | adapt(F f) {return adapt_t<F,void>(f);} | ||
+ | |||
+ | Kod znajduje się w pliku [[media:Dev_null.h | dev_null.h]]. | ||
+ | </div></div> | ||
+ | |||
+ | {{cwiczenie|3|| | ||
+ | |||
+ | Napisz iterator, który nic nie robi, ignorując przypisywane do niego elementy. | ||
+ | }} | ||
+ | |||
+ | <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"> | ||
+ | Korzystamy z prostej klasy proxy: | ||
+ | |||
+ | struct sink { | ||
+ | void operator<nowiki> =</nowiki> (const T&) {}; | ||
+ | }; | ||
+ | |||
+ | której operator przypisania "połyka" swój argument. | ||
+ | Kod znajduje się w pliku [[media:Dev_null.h | dev_null.h]]. | ||
+ | </div></div> | ||
+ | |||
+ | {{cwiczenie|4|| | ||
+ | |||
+ | Zaimplementuj opisany w wykładzie iterator, który działa podaną funkcją na | ||
przypisywane obiekty. | przypisywane obiekty. | ||
+ | }} | ||
+ | |||
+ | <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"> | ||
+ | Iterator | ||
+ | |||
+ | template<typename F,typename T> | ||
+ | class exec_iterator_t: public std::iterator<std::output_iterator_tag,T> | ||
+ | { | ||
+ | F _fun; | ||
+ | |||
+ | oparty jest o zagnieżdżoną klasę proxy: | ||
+ | |||
+ | struct do_it { | ||
+ | exec_iterator_t *_parent; | ||
+ | do_it(exec_iterator_t *parent):_parent(parent) {}; | ||
+ | void operator<nowiki> =</nowiki> (const T& x) { _parent->_fun(x);} | ||
+ | };<br> | ||
+ | do_it _proxy; | ||
+ | |||
+ | której operator przypisania wywołuje podaną funkcje na wartości mu | ||
+ | przekazanej. Operator <tt>*</tt> zwraca obiekt proxy, a operatory | ||
+ | <tt>++</tt> nie robią nic: | ||
+ | |||
+ | public: | ||
+ | exec_iterator_t(F fun):_fun(fun),_proxy(this) {}; | ||
+ | do_it &operator*(){return _proxy;}; | ||
+ | exec_iterator_t &operator++() {return *this;} | ||
+ | void operator++(int) {} | ||
+ | }; | ||
+ | |||
+ | Do utworzenia iteratora używamy szablon funkcji | ||
+ | |||
+ | template<typename T,typename F> | ||
+ | exec_iterator_t<F,T> exec_iterator(F f){ | ||
+ | return exec_iterator_t<F,T>(f); | ||
+ | }; | ||
+ | |||
+ | korzystając z automatycznej dedukcji typów. | ||
+ | |||
+ | Kod znajduje się w pliku [[media:Exec_iterator.h | exec_iterator.h]]. | ||
+ | </div></div> |
Aktualna wersja na dzień 10:48, 2 paź 2006
Ćwiczenie 1
Napisz algorytm for_each
który działałby na dwu zakresach.
template<typename InputIterator1, typename InputIterator2, typename BinaryFunction op> BinaryFunction for_each(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, BinaryFunction op);
Algorytm ma działać tak jak standardowy for_each
, tyle że funkcja
op
ma być stosowana do par elementów:
op(*first1,*first2); op(*(first1+1),*(first2+1); ...
Rozwiązanie
Ćwiczenie 2
Zaimplementuj opisany na wykładzie adapter, który opakowuje funkcję lub funktor, ignorując zwracaną przez nie wartość,, i zwracający zamiast niej jakąś wartość wybranego typu. Np.:
double f(int); adapt(f,7)(0);
wywołuje f(0) i zwraca 7.
double f(int); adapt(f)(0);
wywołuje f(0) i nie zwraca żadnej wartości.
Rozwiązanie
Ćwiczenie 3
Napisz iterator, który nic nie robi, ignorując przypisywane do niego elementy.
Rozwiązanie
Ćwiczenie 4
Zaimplementuj opisany w wykładzie iterator, który działa podaną funkcją na przypisywane obiekty.
Rozwiązanie