Zaawansowane CPP/Ćwiczenia 6: Funkcje typów i inne sztuczki: Różnice pomiędzy wersjami
Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Nie podano opisu zmian |
Nie podano opisu zmian |
||
(Nie pokazano 12 wersji utworzonych przez 3 użytkowników) | |||
Linia 1: | Linia 1: | ||
{{cwiczenie|1|| | |||
Napisz szablon, który sprawdza czy jego parametr | |||
posiada typ stowarzyszony <tt>value_type</tt>, np.: | |||
<nowiki> has_value_type<std::vector<int> >::yes</nowiki> | |||
powinno mieć wartość <code><nowiki>true</nowiki></code>, a | |||
</ | |||
<nowiki> has_value_type<int>::yes</nowiki> | |||
wartość <code><nowiki>false</nowiki></code>. | |||
</ | }} | ||
<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 wzorować się na szablonie [[media:Is_class.cpp | is_class]]. | |||
</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"> | |||
Zasada jest taka sama, jak w przypadku sprawdzania czy dany typ jest klasą. Trzeba tylko wybrać odpowiedni argument pierwszej funkcji testującej. Odpowiednie wyrażenie to <tt>U::value_type</tt>, które nie jest poprawne dla typów <tt>U</tt> nie posiadających stowarzyszonego typu <tt>value_type</tt>. Definiujemy więc: | |||
template<typename U> static one test(typename U::value_type ); | |||
Reszta jest jak dla Is_class. Całość kodu jest zamieszczona w pliku [[media:Has_value_type.cpp | has_value_type.cpp]] | |||
</div></div> | |||
{{cwiczenie|2|| | |||
Napisz szablon, który sprawdza czy jeden z jego | |||
argumentów dziedziczy z drugiego. | argumentów dziedziczy z drugiego. | ||
}} | |||
<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"> | |||
Wskaźnik <code><nowiki>Derived*</nowiki></code> może być konwertowany do <code><nowiki>Base*</nowiki></code> tylko jeśli <code><nowiki>Derived</nowiki></code> dziedziczy z <code><nowiki>Base</nowiki></code> lub <code><nowiki>Base</nowiki></code> jest typem <tt>void</tt>. Można więc wykorzystać szablon <tt>Convertible</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"> | |||
Zgodnie ze wskazówką sprawdzamy, korzystając z klasy <tt>Is_convertible</tt>, czy <code><nowiki>Derived*</nowiki></code> może być skonwertowany do <code><nowiki>Base*</nowiki></code> i czy <code><nowiki>Base</nowiki></code> nie równa się <tt>void</tt>: | |||
template<typename Derived, typename Base > struct Is_derived { | |||
enum {yes = Is_convertible<Derived*,Base*>::yes && | |||
!Is_convertible<Base*,void*>::same_type | |||
}; | |||
}; | |||
Proszę zwrócić uwagę, że porównywane są typy <tt>Base*</tt> i <tt>void*</tt>. Porównanie typów <tt>Base</tt> i <tt>void</tt> za pomocą szablonu <tt>Convertible</tt> nie jest możliwe, bo prowadzi do nielegalnego wyrażenia <tt>test(void)</tt>. Całość kodu jest zawarta w pliku [[media:Derived.cpp | derived.cpp]]. | |||
</div></div> | |||
{{cwiczenie|3|| | |||
Napisz szablon, który sprawdza czy dany typ jest wymieniony w podanej | |||
liście typów. Np.: | liście typów. Np.: | ||
<nowiki> in<int,TypeList<int,TypeList<double,NullType> >>::yes | <nowiki> in<int,TypeList<int,TypeList<double,NullType> >>::yes</nowiki> | ||
</nowiki> | |||
jest prawdziwe, a | jest prawdziwe, a | ||
<nowiki> in<int,TypeList<char,TypeList<double,NullType> >>::yes | <nowiki> in<int,TypeList<char,TypeList<double,NullType> >>::yes</nowiki> | ||
</nowiki> | |||
jest fałszywe. | jest fałszywe. | ||
}} | |||
<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"> | |||
Idea rozwiązania jest następująca: jeśli nasz podany typ jest głową listy, to wiemy, że należy do listy: | |||
template<typename T, typename Tail> struct In<T,TypeList<T,Tail> >{ | |||
enum {yes=1}; | |||
}; | |||
Jeśli nie, to sprawdzamy czy należy do ogona: | |||
Implementacja indeksowania listy typów podana na wykładzie | template<typename T, typename TL> struct In { | ||
przypadku przekroczenia zakresu | enum {yes=In<T, typename TL::Tail>::yes }; | ||
mniej | }; | ||
Jeśli dojdziemy do końca listy, czyli do <tt>Null_type</tt>, oznacza to, że szukanego typu nie ma na liście. | |||
template<typename T> struct In<T,Null_type> { | |||
enum {yes=0}; | |||
}; | |||
Kod zawarty jest w pliku [[media:Typelist.h | typelist.h]]. | |||
</div></div> | |||
{{cwiczenie|4|| | |||
Implementacja indeksowania listy typów podana na wykładzie w | |||
przypadku przekroczenia zakresu powoduje błąd kompilacji. Napisz | |||
mniej restrykcyjną wersję tego szablonu, która w takiej sytacji "zwraca" | |||
typ: | typ: | ||
<nowiki> struct Empty_type {}; | <nowiki> struct Empty_type {};</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"> | |||
Rozwiązanie jest podobne jak dla szablonu <tt>At</tt>: | |||
template<int N,typename T> struct At2 { | |||
typedef typename At2<N-1, typename T::Tail>::Result Result; | |||
}; | |||
template<typename H,typename T> struct At2<1,TypeList<H,T> > { | |||
typedef H Result; | |||
}; | |||
Dodajemy tylko specjalizację, która w przypadku napotkania końca listy zwraca <tt> Empty_type</tt>: | |||
template<int N> struct At2<N,Null_type> { | |||
typedef Empty_type Result; | |||
}; | |||
Kod zawarty jest w pliku [[media:Typelist.h | typelist.h]]. | |||
</div></div> |
Aktualna wersja na dzień 10:30, 2 paź 2006
Ćwiczenie 1
Napisz szablon, który sprawdza czy jego parametr posiada typ stowarzyszony value_type, np.:
has_value_type<std::vector<int> >::yes
powinno mieć wartość true
, a
has_value_type<int>::yes
wartość false
.
Podpowiedź
Rozwiązanie
Ćwiczenie 2
Napisz szablon, który sprawdza czy jeden z jego argumentów dziedziczy z drugiego.
Podpowiedź
Rozwiązanie
Ćwiczenie 3
Napisz szablon, który sprawdza czy dany typ jest wymieniony w podanej liście typów. Np.:
in<int,TypeList<int,TypeList<double,NullType> >>::yes
jest prawdziwe, a
in<int,TypeList<char,TypeList<double,NullType> >>::yes
jest fałszywe.
Rozwiązanie
Ćwiczenie 4
Implementacja indeksowania listy typów podana na wykładzie w przypadku przekroczenia zakresu powoduje błąd kompilacji. Napisz mniej restrykcyjną wersję tego szablonu, która w takiej sytacji "zwraca" typ:
struct Empty_type {};
Rozwiązanie