-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtemplate_basics.tex
295 lines (231 loc) · 9.75 KB
/
template_basics.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
\section{template basics}
\subsection{Über templates}
\begin{frame}[fragile]{Was sind templates?}
templates sind: Vorlagen (Schablonen) für Klassen und Funktionen
\pause
\vspace{2em}
\lstinputlisting[linerange=begin-max_schablone]{cpp-code/function-templates.cpp}
\pause
\begin{lstlisting}
class MyRingbuffer_int { int* p; /*...*/ };
class MyRingbuffer_short;
class MyRingbuffer_double;
class MyRingbuffer_MyType;
\end{lstlisting}
\end{frame}
\begin{frame}{Zum Einstellen}
templates sind
\begin{itemize}
\item mächtiger als der Präprozessor
\item schwieriger als der Rest von C++ zusammen
\end{itemize}
\pause
\vspace{1em}
Beides nicht ganz wahr!
\begin{itemize}
\item man kann ganz wenige Dinge nur mit dem Präprozessor tun (und viele Dinge nur mit templates)
\item die grundlegende Verwendung von templates ist einfach
\end{itemize}
\end{frame}
\begin{frame}{Für den Hinterkopf}
Wichtig bei templates ist:
\begin{itemize}
\item templates erzeugen Klassen und Funktionen
\item aber keinen echten Quelltext
\item templates werden unmittelbar vor der Übersetzung verarbeitet
\item Fokus: statische Typsicherheit und Umgang mit Typen
\end{itemize}
\end{frame}
\subsection{Essentials zur Verwendung}
\begin{frame}[t]{Funktions-templates: Beispiel}
% später: type deduction
Ziel: Anhand einer Vorlage all diese Funktionen erzeugen \emph{lassen}.\\
D.h.: Vorlage + Typ $\implies$ Funktion
\vspace{2em}
\onslide*<+> { \lstinputlisting[linerange=begin-max_schablone]{cpp-code/function-templates.cpp} }
\lstset{morecomment=[l][\invisible]template}
\onslide*<+> { \lstinputlisting[linerange=begin-max_template]{cpp-code/function-templates.cpp} }
\lstset{deletecomment=[l]template}
\onslide*<+-> { \lstinputlisting[linerange=begin-max_template]{cpp-code/function-templates.cpp} }
\end{frame}
\begin{frame}[fragile]{Funktions-templates: Syntax}
\begin{block}{Definition eines Funktions-templates}
\lstinputlisting[linerange=max_template-max_template_short, firstnumber=0]{cpp-code/function-templates.cpp}
\end{block}
Ein template liefert dem Compiler eine Konstruktionsvorschrift:\\
Vorlage + Parameter $\implies$ Funktion
\pause
\vspace{1em}
\begin{block}{Veranschaulichung: int als Parameter T}
\lstinputlisting[linerange=no_template-no_template_end, firstnumber=last]{cpp-code/function-templates.cpp}
\end{block}
\end{frame}
\begin{frame}{Verwendung von Funktions-templates}
Ein Funktions-template ist eine Vorlage, und keine Funktion! (selbes gilt für class templates)\\
$\implies$ es bedarf des Konstruktionsschrittes \emph{function template} $\rightarrow$ \emph{function}\\
Nennt sich: Instanziierung (des Funktions-templates)
\vspace{1em}
Warum nicht gleich für alle möglichen Parameter instanziieren?\\
\pause
\alert<+>{code bloat!}
\uncover<+->
{
\vspace{1em}
Also nur Instanziieren, wenn tatsächlich benötigt. Funktioniert wie?
}
\uncover<+->
{
\vspace{1em}
Geschieht \alert{automagisch bei der Verwendung}! Hier liegt der Unterschied zu macros usw.!
}
\end{frame}
\begin{frame}{Implizite Instanziierung}
\begin{block}{Aufrufen einer template-Funktion}
\lstinputlisting[linerange=call0-call1, firstnumber=0]{cpp-code/function-templates.cpp}
\end{block}
\pause
\begin{itemize}
\item Compiler erkennt: hier wird eine Schablone benannt und eine Instanz benötigt. \\
\item $\implies$ Compiler instanziiert das template, Funktionsaufruf wird mit Instanz verbunden.
\item Das fertige Programm wird an dieser Stelle die entstandene Funktion aufrufen.
\end{itemize}
\pause
\lstinputlisting[linerange=call1-, firstnumber=last]{cpp-code/function-templates.cpp}
Eine andere Funktion wird erzeugt!
Es wird nur eine Instanz je Satz von template-Parametern erzeugt pro \emph{translation unit} und nicht für jeden Aufruf eine.
\end{frame}
\begin{frame}[fragile]{Sichtbarkeit und Instanziierung}
\alert<+>{Bisher:}
\begin{itemize}
\item kann eine Funktion aufrufen, wenn die Deklaration vorhanden ist
\item die Funktion kann (external linkage) in einer anderen translation unit definiert sein
\end{itemize}
\onslide<+->
\vspace{0.5em}
\alert<.>{templates:}
\begin{itemize}
\item Instanziierung erfordert vorherige \emph{Definition}!
\item $\implies$ Funktionsaufrufe von noch nicht instanziierten templates erfordern die Definition (den Körper) der Funktion weiter oben in \emph{derselben} translation unit
\end{itemize}
\onslide<+->
\vspace{0.5em}
\begin{description}[leftmargin=3.5em]
\item[\emph{common solution}] templates inkl. Definitionen in die Header!\\
\item[\emph{Problem}] One definition rule {\tiny (darf nicht mehr als eine Definition im gesamten Programm haben) }\\
\item[\emph{Umgehung}] internal linkage (\verb|static|) oder \verb|inline|
\end{description}
\end{frame}
\begin{frame}{templates \& headers}
\begin{columns}[t]
\column{0.5\textwidth}
\emph{header.h}
\lstinputlisting[linerange=header-header_end]{cpp-code/template-header.cpp}
\pause
\column{0.5\textwidth}
\emph{foobar.cpp}
\lstinputlisting[linerange=foobar.cpp-main.cpp, firstnumber=0]{cpp-code/template-header.cpp}
\pause
\emph{main.cpp}
\lstinputlisting[linerange=main.cpp-, firstnumber=0]{cpp-code/template-header.cpp}
\end{columns}
\end{frame}
\subsection{Mehr zu templates}
\begin{frame}[fragile]{template parameters}
Die template-declaration enthält wie Funktions-Deklarationen eine Menge von Parametern:
\begin{lstlisting}
void foo(int, double, MyType, int);
template < typename T, typename MyTemplateParam,
class x >
void bar();
\end{lstlisting}
Im Kontext einer template-declaration sind \verb|typename| und \verb|class| semantisch identisch.
\pause
Ein template-Parameter empfängt bei der Instanziierung entweder
\begin{itemize}
\item einen Typen, d.h. den Namen einer \verb|class|, \verb|struct|, \verb|union| $\Rightarrow$ template type-parameter
\item oder einen Wert ähnlich wie bei einem Funktionsaufruf $\Rightarrow$ template non-type-parameter \alert{(später!)}
\end{itemize}
\end{frame}
\begin{frame}[fragile]{class templates}
Grundsätzlich: Wie function templates
\begin{columns}
\column{0.5\textwidth}
\begin{lstlisting}
template < typename T >
class MyRingbuffer {
T* data_member;
T memfun(int);
/* work with T */
};
\end{lstlisting}
\column{0.5\textwidth}
\begin{lstlisting}
class MyRingbuffer_double {
double* data_member;
double memfun(int);
/* work with double */
};
\end{lstlisting}
\end{columns}
\pause
\vspace{1em}
Gleiche Probleme:
\begin{itemize}
\item Implizite Instanziierung bei Verwendung (z.B. Deklaration eines »Dinges«)
\item Definition in den Header
\item linkage der member functions??
\end{itemize}
\end{frame}
\begin{frame}[t]{class template member functions}
\vspace{-2em}
\begin{columns}[t]
\column{0.5\textwidth}
\onslide*<+> { \lstinputlisting[linerange=inline-anon_namespace]{cpp-code/template-mem-fun.cpp} }
\onslide*<+> { \lstinputlisting[linerange=inline-func_decl]{cpp-code/template-mem-fun.cpp} }
% Koios: dirty hack to uncover lines within the listing:
% 1) introduce a /$$/ at the beginning of the lines in the listing file
% 2) use two \lstinputlisting-s
% 3) the first \lstinputlisting shall interpret /$ as a delimiter for an invisible LINE comment
% 4) the second one shall interpret /$ as the start and $/ as the end delimiter for an invisible two-delimiter comment
\lstset{morecomment=[l][\invisible]/\$}
\onslide*<+> { \lstinputlisting[linerange=inline-implicit_inline]{cpp-code/template-mem-fun.cpp} }
\lstset{deletecomment=[l]/\$, morecomment=[is]{/\$}{\$/}}
\onslide*<+-> { \lstinputlisting[linerange=inline-implicit_inline]{cpp-code/template-mem-fun.cpp} }
\lstset{deletecomment=[is]{/\$}{\$/}}
\column{0.5\textwidth}
\onslide*<+-> { \lstinputlisting[linerange=implicit_inline-ctmft]{cpp-code/template-mem-fun.cpp} }
\end{columns}
\end{frame}
\begin{frame}[t]{class template member function templates}
\onslide*<+> { \lstinputlisting[linerange=ctmft-ctmft_def]{cpp-code/template-mem-fun.cpp} }
\onslide*<+> { \lstinputlisting[linerange=ctmft-]{cpp-code/template-mem-fun.cpp} }
\end{frame}
\begin{frame}[t, fragile]{intricacies: qualified-id, template}
\begin{block}{unqualified name lookup = weird}
Generell eine gute Idee: alles qualifiziert (explizit) hinschreiben, z.B. \verb|mynamespace::MyClass::MyStuff| \\
Bei templates ist dies extrem wichtig!
\end{block}
\pause
\begin{block}{keyword \texttt{template} (Standard, 14.2/4)}
Folgt auf ein \verb|.| \verb|->| oder \verb|::| der Name eines templates, so muss vor diesem Namen das Keyword \verb|template| eingefügt werden (14.2/4).
\vspace{-1.5em}
\begin{columns}[t]
\column{0.475\textwidth}
\uncover<+-> { \lstinputlisting[linerange=template-template_usage]{cpp-code/template-intricacies.cpp} }
\column{0.525\textwidth}
% Koios: again that dirty hack....
\lstset{morecomment=[l][\invisible]/\$}
\onslide*<+> { \lstinputlisting[linerange=template_usage-typename]{cpp-code/template-intricacies.cpp} }
\lstset{deletecomment=[il]/\$, morecomment=[is]{/\$}{\$/}}
\onslide*<+-> { \lstinputlisting[linerange=template_usage-typename]{cpp-code/template-intricacies.cpp} }
\end{columns}
\end{block}
\end{frame}
\begin{frame}[t, fragile]{intricacies: dependent names, typename}
\alert{Nur innerhalb von template-Definitionen!}
\begin{block}{keyword \texttt{typename} (Standard, 14.6/2-3)}
Wird ein Typ mittels \emph{qualified-id} benannt (mit \verb|::|), und es taucht ein template Parameter (auch implizit) auf, so muss vor den ganzen Ausdruck ein \verb|typename| gestellt werden.
\pause
\lstinputlisting[linerange=typename-]{cpp-code/template-intricacies.cpp}
\end{block}
\end{frame}