Zaawansowane CPP/Ćwiczenia 11: Funktory: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
 
(Nie pokazano 23 wersji utworzonych przez 2 użytkowników)
Linia 1: Linia 1:
'''Zadanie 1 '''  Zaimplementuj adapter <code><nowiki>compose_f_gx_hy</nowiki></code>
+
{{cwiczenie|1||
 +
 
 +
Zaimplementuj adapter <code><nowiki>compose_f_gx_hy</nowiki></code>
 
realizujący złożenie dwuargumentowe <math>\displaystyle f(g(x),h(y))</math>.
 
realizujący złożenie dwuargumentowe <math>\displaystyle f(g(x),h(y))</math>.
 +
}}
 +
 +
<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">
 +
Zobacz plik [[media:Compose_f_gx_hy.h | compose_f_gx_hy.h]].
 +
</div></div>
 +
 +
{{cwiczenie|2||
 +
 +
Korzystając z klasy <code><nowiki>functor_traits</nowiki></code>
 +
zaimplementuj adpter <code><nowiki>bind1st</nowiki></code>, który bedzie działał zarówno dla funktorów jedno-, jak i dwuargumentowych.
 +
}}
 +
 +
<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">
 +
W klasie <tt>binder1st</tt> umieszczamy dwa operatory nawiasów:
 +
 +
template<typename F> class binder1st :
 +
public  bind1st_f_type<typename functor_traits<F>::f_type>::f_type {
 +
  typedef  typename functor_traits<F>::arg1_type  bind_type;<br> 
 +
  const bind_type _val;
 +
  F _op;
 +
  public:
 +
  binder1st(F op,bind_type val):_op(op), _val(val) {};<br>
 +
  typename F::result_type operator()(typename functor_traits<F>::arg2_type x) {
 +
    return _op(_val,x);
 +
  }
 +
  typename F::result_type operator()() {
 +
    return _op(_val);
 +
  }
 +
};
 +
 +
Dzięki konkretyzacji na żądanie wygenerowany zostanie tylko ten, którego użyjemy w kodzie. Szablon <tt>bind1st_f_type</tt> służy do określenia typu funktora po związaniu pierwszego argumentu. Do jego implemenatcji wykorzystujemy specjalizacje częściowe:
 +
 +
template<typename F> struct bind1st_f_type;<br>
 +
template<typename A1,typename A2,typename R>
 +
struct bind1st_f_type<std::binary_function<A1,A2,R> > {
 +
  typedef std::unary_function<A2,R> f_type;
 +
};<br>
 +
template<typename A1,typename R>
 +
struct bind1st_f_type<std::unary_function<A1,R> > {
 +
  typedef generator<R> f_type;
 +
};
 +
 +
Całość kodu znajduje się w pliku [[media:Bind.h | bind.h]].
 +
</div></div>
 +
 +
{{cwiczenie|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 <tt>macro</tt> 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);
 +
}}
 +
 +
<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">
 +
Zobacz plik [[media:Macro.h | macro.h]].
 +
</div></div>
 +
 +
{{cwiczenie|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);<br>
 +
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)
 +
}}
 +
<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();
 +
void g(double);
 +
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);*/
 +
 +
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">
 +
Zaczynamy od implemenatcji adaptera <tt>call</tt>. W tym celu definiujemy
 +
szablon:
 +
 +
template<typename F,typename A1,typename A2> struct call_t2: public
 +
std::binary_function<A1,
 +
                      A2,
 +
                      typename functor_traits<F>::result_type> {
 +
  typedef typename functor_traits<F>::result_type result_type;
 +
  typedef typename functor_traits<F>::arg1_type arg1_type;
 +
  typedef typename functor_traits<F>::arg2_type arg2_type;<br>
 +
  F _f;<br>
 +
public:
 +
call_t2(F f):_f(f) {};
  
'''Zadanie 2 ''' Korzystając z klasy <code><nowiki>functor_traits</nowiki></code>
+
który wyposażamy w trzy funkcje:
zaimplementuj adpter <code><nowiki>bind1st</nowiki></code> który bedzie działał zarówno dla
+
   
jedno i dwuargumentowych funktorów.
+
  result_type call(A1 a1,A2 a2,
 +
                  generator<result_type>) {
 +
    return _f();
 +
  };
 +
  result_type call(A1 a1,A2 a2,
 +
                  std::unary_function<arg1_type,result_type>) {
 +
    return _f(a1);
 +
  };
 +
  result_type call(A1 a1,A2 a2,
 +
                  std::binary_function<arg1_type,arg2_type,result_type>) {
 +
    return _f(a1,a2);
 +
  };
  
'''Zadanie 3 '''   Rozszerz powyższy adapter tak, aby
+
Ostatni argument służy do tylko do przeciążenia funkcji wykorzystanego w operatorze nawiasów:
działa  również dla jedno lub dwuargumentowych funkcji bez konieczności ich opakowywania.
+
 +
   result_type operator()(A1 a1,A2 a2) {
 +
    return call(a1,a2,typename functor_traits<F>::f_type());
 +
  };
  
'''Zadanie 4 '''
+
Jak zwykle dodajemy funkcję:
 +
 +
template<typename A1,typename A2,typename F> call_t2<F,A1,A2> call(F f) {
 +
return call_t2<F,A1,A2>(f);}
  
Zaimplementuj funktor impelemetujący, składanie funkcji poprzez
+
Podobnie definiujemy jednoargumentową wersję tego szablonu <tt>call_t1</tt> i przeciążoną funkcję:
wykonywanie ich po kolei:
 
  
  <nowiki> macro1(f1,f2)(x)</nowiki>
+
  template<typename A1,typename F> call_t1<F,A1> call(F f) {
 +
return call_t1<F,A1>(f);}
  
wykonuje <code><nowiki>f1(x);f2(x);</nowiki></code>. Wartości zwracane przez te funkcje są
+
Całość kodu znajduje się w pliku [[media:Call.h | call.h]].
ignorowane. Podobnie dla funkcji <code><nowiki>macro2(f1,f2)</nowiki></code>, która ma zwrócić
 
funktor dwuargumentowy.
 
  
'''Zadanie 5 ''' 
+
Implementując adapter <tt>macro</tt> musimy umieć poznać która z dwu przekazanych funkcji ma wiecej argumentów. Używamy w tym celu szablonu <tt>If_then_else</tt>:
  
Zmodyfikuj powyższy szablon tak aby mogły być do niego przekazywane również funkcje bezargumentowe:
+
template<typename F1,typename F2> struct macro_type {
 +
  typedef typename If_then_else<
 +
    (size_t)functor_traits<F1>::n_args
 +
      ><nowiki> =</nowiki>       
 +
    (size_t)functor_traits<F2>::n_args ,
 +
    typename functor_traits<F1>::f_type,
 +
    typename functor_traits<F2>::f_type>::Result  m_type;
 +
};
  
<nowiki> int f();
+
Korzystając z <tt>macro_type</tt> i <tt>call</tt> możemy zaimplementować szablon:
void g(double);
 
  
macro1(f,g)(x);</nowiki>
+
template<typename F1,typename F2>  class macro_t :
 +
public macro_type<F1,F2>::m_type {
 +
  public:
 +
  typedef void result_type ;
  
spowdoduje wywołanie, <code><nowiki>f();g(x)</nowiki></code>.
+
Proszę zwrócić uwagę, że dziedzicząc z <tt>macro_type<F1,F2>::m_type</tt>
 +
defiuniujemy poprawne typy argumentów fuktora, ale niekoniecznie dobry
 +
typ wartości zwracanej. Dlatego redefinujemy go potem na <tt>void</tt>.
 +
Całość kodu znajduje się w pliku [[media:Mixed_macro.h | mixed_macro.h]].
 +
</div></div>

Aktualna wersja na dzień 10:47, 2 paź 2006

Ćwiczenie 1

Zaimplementuj adapter compose_f_gx_hy realizujący złożenie dwuargumentowe .

Rozwiązanie

Ć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.

Rozwiązanie

Ć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);
Rozwiązanie

Ć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