Zaawansowane CPP/Ćwiczenia 12: Używanie funktorów: Różnice pomiędzy wersjami
Nie podano opisu zmian |
Nie podano opisu zmian |
||
Linia 41: | Linia 41: | ||
przypisywane obiekty. | przypisywane obiekty. | ||
}} | }} | ||
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) { | |||
for(;first1!<nowiki> =</nowiki> last1;++first1,++first2) | |||
op(*first1,*first2); | |||
return op; | |||
} | |||
Kod znajduje się w pliku | |||
{mod14/exercises/for_each.h}<tt>foreach.h</tt> | |||
'''Rozwiązanie 2 ''' | |||
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; | |||
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 {Result <nowiki> =</nowiki> void} 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 | |||
{mod14/exercises/dev_null.h}<tt>devnull.h</tt> | |||
'''Rozwiażanie 3 ''' | |||
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 | |||
{mod14/exercises/dev_null.h}<tt>devnull.h</tt> | |||
'''Rozwiązanie 4 ''' | |||
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);} | |||
}; | |||
do_it _proxy; | |||
której operator przypisanie wywołuje podaną funkcje na wartości mu | |||
przekazanej. Operator {*} zwraca obiekt proxy, a operatory | |||
{++} 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 | |||
{mod14/exercises/exec_iterator.h}<tt>execiterator.h</tt> |
Wersja z 11:19, 25 wrz 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); ...
Ć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 wraca żadnej wartości.
Ćwiczenie 3
Napisz iterator, który nic nie robi, ignorując przypisywane do niego elementy.
Ćwiczenie 4
Zaimplementuj opisany w wykładzie iterator, który działa podaną funkcją na przypisywane obiekty.
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) {
for(;first1! = last1;++first1,++first2) op(*first1,*first2);
return op;
}
Kod znajduje się w pliku {mod14/exercises/for_each.h}foreach.h
Rozwiązanie 2
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; 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 {Result = void} 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 {mod14/exercises/dev_null.h}devnull.h
Rozwiażanie 3
Korzystamy z prostej klasy proxy:
struct sink { void operator = (const T&) {}; };
której operator przypisania "połyka" swój argument. Kod znajduje się w pliku {mod14/exercises/dev_null.h}devnull.h
Rozwiązanie 4
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 = (const T& x) { _parent->_fun(x);} };
do_it _proxy;
której operator przypisanie wywołuje podaną funkcje na wartości mu przekazanej. Operator {*} zwraca obiekt proxy, a operatory {++} 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 {mod14/exercises/exec_iterator.h}execiterator.h