|
14 | 14 | \begin{cppcode}
|
15 | 15 | template<typename T>
|
16 | 16 | const T & max(const T &a, const T &b) {
|
17 |
| - return a > b ? a : b; |
| 17 | + return b < a ? a : b; |
18 | 18 | }
|
19 | 19 | template<typename T>
|
20 | 20 | struct Vector {
|
|
33 | 33 | \item they are compiled for each instantiation
|
34 | 34 | \item they need to be defined before used
|
35 | 35 | \begin{itemize}
|
36 |
| - \item so all templated code has to be in headers |
| 36 | + \item so all template code must typically be in headers |
| 37 | + \item or declared to be available externally (\mintinline{cpp}{extern template}) |
37 | 38 | \end{itemize}
|
38 |
| - \item this may lead to longer compilation times and bigger libraries |
| 39 | + \item this may lead to longer compilation times and bigger binaries |
39 | 40 | \end{itemize}
|
40 | 41 | \end{alertblock}
|
41 | 42 | \newsavebox{\codepiece}
|
|
104 | 105 | \end{frame}
|
105 | 106 |
|
106 | 107 | \begin{frame}[fragile]
|
107 |
| - \frametitlecpp[98]{Templates implementation} |
| 108 | + \frametitlecpp[98]{Template implementation} |
108 | 109 | \begin{cppcode*}{}
|
109 | 110 | template<typename KeyType=int, typename ValueType=KeyType>
|
110 | 111 | struct Map {
|
|
131 | 132 | \begin{itemize}
|
132 | 133 | \item integral types, pointer, enums in \cpp98
|
133 | 134 | \item \mintinline{cpp}{auto} in \cpp17
|
134 |
| - \item floats and literal types in \cpp20 |
| 135 | + \item floating-point and literal types in \cpp20 |
135 | 136 | \end{itemize}
|
136 | 137 | \end{block}
|
137 | 138 | \begin{cppcode*}{}
|
|
145 | 146 | \end{frame}
|
146 | 147 |
|
147 | 148 | \begin{frame}[fragile]
|
148 |
| - \frametitlecpp[98]{Templates} |
| 149 | + \frametitlecpp[98]{Template specialization} |
149 | 150 | \begin{block}{Specialization}
|
150 |
| - templates can be specialized for given values of their parameter |
| 151 | + Templates can be specialized for given values of their parameter |
151 | 152 | \end{block}
|
| 153 | + \small |
152 | 154 | \begin{cppcode*}{}
|
153 | 155 | template<typename F, unsigned int N>
|
154 |
| - struct Polygon { |
155 |
| - Polygon(F radius) : m_radius(radius) {} |
156 |
| - F perimeter() {return 2*N*sin(PI/N)*m_radius;} |
157 |
| - F m_radius; |
158 |
| - }; |
| 156 | + struct Polygon { ... }; // primary template |
159 | 157 |
|
160 |
| - template<typename F> |
| 158 | + template<typename F> // partial specialization |
161 | 159 | struct Polygon<F, 6> {
|
162 | 160 | Polygon(F radius) : m_radius(radius) {}
|
163 |
| - F perimeter() {return 6*m_radius;} |
| 161 | + F perimeter() { return 6*m_radius; } |
164 | 162 | F m_radius;
|
165 | 163 | };
|
| 164 | + template<> // full specialization |
| 165 | + struct Polygon<int, 6> { |
| 166 | + Polygon(int radius) : m_radius(radius) {} |
| 167 | + int perimeter() { return 6*m_radius; } |
| 168 | + int m_radius; |
| 169 | + }; |
| 170 | + \end{cppcode*} |
| 171 | +\end{frame} |
| 172 | + |
| 173 | +\begin{advanced} |
| 174 | + |
| 175 | +\begin{frame}[fragile] |
| 176 | + \frametitlecpp[98]{Template argument deduction} |
| 177 | + \begin{block}{Template argument deduction} |
| 178 | + \begin{itemize} |
| 179 | + \item Template arguments deduced from (function) arguments |
| 180 | + \item Template arguments can always be specified explicitly |
| 181 | + \item Only for function templates (Before \cpp14) |
| 182 | + \end{itemize} |
| 183 | + \end{block} |
| 184 | + \begin{cppcode*}{} |
| 185 | + template <typename T, typename U> |
| 186 | + void f(T t, U u) { ... } |
| 187 | + |
| 188 | + f(42, true); // deduces T=int, U=bool |
| 189 | + // calls f<int, bool>(42, true); |
| 190 | + f<float>(42, true); // sets T=float, deduces U=bool |
| 191 | + // calls f<float, bool>(42, true); |
| 192 | + // 42 converted to float before call |
166 | 193 | \end{cppcode*}
|
167 | 194 | \end{frame}
|
168 | 195 |
|
| 196 | +\begin{frame}[fragile] |
| 197 | + \frametitlecpp[11]{Template argument deduction} |
| 198 | + \begin{block}{Deduced contexts} |
| 199 | + \begin{itemize} |
| 200 | + \item Compiler can even deduce template arguments inside certain expressions (pattern matching) |
| 201 | + \item See \href{https://en.cppreference.com/w/cpp/language/template_argument_deduction}{cppreference} for details |
| 202 | + \end{itemize} |
| 203 | + \end{block} |
| 204 | + \begin{cppcode*}{} |
| 205 | + template <typename T> |
| 206 | + void f(T* p) { ... } |
| 207 | + |
| 208 | + const int * ip = ...; |
| 209 | + f(ip); // deduces T=const int |
| 210 | + |
| 211 | + template <typename T, std::size_t N> |
| 212 | + void g(std::array<T*, N> a) { ... } |
| 213 | + |
| 214 | + std::array<int*, 3> aip = ...; |
| 215 | + g(aip); // deduces T=int, N=3 |
| 216 | + \end{cppcode*} |
| 217 | +\end{frame} |
| 218 | + |
| 219 | +\begin{frame}[fragile] |
| 220 | + \frametitlecpp[11]{Template argument deduction} |
| 221 | + \begin{block}{Non-deduced contexts} |
| 222 | + \begin{itemize} |
| 223 | + \item Deduction from certain expressions is impossible/forbidden |
| 224 | + \end{itemize} |
| 225 | + \end{block} |
| 226 | + \begin{overprint} |
| 227 | + \onslide<1> |
| 228 | + \begin{alertblock}{} |
| 229 | + \footnotesize |
| 230 | + \begin{cppcode*}{gobble=2} |
| 231 | + template <typename C> |
| 232 | + void f(typename C::value_type v) { ... } |
| 233 | + f(std::vector<int>{...}); // cannot deduce C |
| 234 | + // from a dependent type |
| 235 | + template <typename T, std::size_t N> |
| 236 | + void g(std::array<T, N * 2> a) { ... } |
| 237 | + g(std::array<int, 4>{...}); // deduces T=int, |
| 238 | + // cannot deduce N from expression |
| 239 | + template <typename T> |
| 240 | + void h(std::vector<T> v) { ... } |
| 241 | + h({1, 2, 3}); // error, braced-initializer list has no type |
| 242 | + h(std::vector<int>{1, 2, 3}); // ok, T=int |
| 243 | + \end{cppcode*} |
| 244 | + \end{alertblock} |
| 245 | + \onslide<2> |
| 246 | + \begin{alertblock}{} |
| 247 | + \footnotesize |
| 248 | + \begin{cppcode*}{gobble=2} |
| 249 | + template <typename C, typename F> |
| 250 | + void reduce(const C& cont, const F& f = std::plus{}); |
| 251 | + reduce(std::vector<int>{...}); // error: cannot deduce F |
| 252 | + // would need: <typename C, typename F = decltype(std::plus{})> |
| 253 | + |
| 254 | + template<typename T> |
| 255 | + const T & max(const T &a, const T &b) { ... } |
| 256 | + int i = 3; |
| 257 | + max(i, 3.14f); // deduces T=int and T=float, error |
| 258 | + // either: max<float>(i, 3.14f); |
| 259 | + // or: max(static_cast<float>(i), 3.14f); |
| 260 | + \end{cppcode*} |
| 261 | + \end{alertblock} |
| 262 | + \end{overprint} |
| 263 | +\end{frame} |
| 264 | + |
| 265 | +\begin{frame}[fragile] |
| 266 | + \frametitlecpp[11]{Template argument deduction} |
| 267 | + \begin{block}{Deduction in partial specializations} |
| 268 | + \begin{itemize} |
| 269 | + \item Partial specializations also deduce template arguments |
| 270 | + \begin{itemize} |
| 271 | + \item with similar rules as for function templates |
| 272 | + \item but some more restrictions (cf.\ \href{https://en.cppreference.com/w/cpp/language/partial_specialization}{cppreference}) |
| 273 | + \end{itemize} |
| 274 | + \end{itemize} |
| 275 | + \end{block} |
| 276 | + \small |
| 277 | + \begin{cppcode*}{} |
| 278 | + template <typename T> |
| 279 | + struct S { ... }; // primary template |
| 280 | + |
| 281 | + template <typename T> |
| 282 | + struct S<T*> { ... }; // specialization 1 |
| 283 | + |
| 284 | + template <typename T, std::size_t N> |
| 285 | + struct S<std::array<T*, N>> { ... }; // specialization 2 |
| 286 | + |
| 287 | + S<int> s1; // prim. tmpl. (T=int) ok, spec. 1/2 invalid |
| 288 | + S<int*> s2; // prim. tmpl. (T=int*) and spec. 1 (T=int) ok |
| 289 | + // spec. 1 is more specialized, will be used |
| 290 | + \end{cppcode*} |
| 291 | +\end{frame} |
| 292 | + |
| 293 | +\begin{frame}[fragile] |
| 294 | + \frametitlecpp[98]{Template argument deduction} |
| 295 | + \begin{block}{Specialization vs.\ overloading} |
| 296 | + \begin{itemize} |
| 297 | + \item For function templates we can choose between specialization and overloading |
| 298 | + \item Partial specialization of function templates is forbidden |
| 299 | + \end{itemize} |
| 300 | + \end{block} |
| 301 | + \small |
| 302 | + \begin{multicols}{2} |
| 303 | + \begin{cppcode*}{} |
| 304 | + template <typename T> |
| 305 | + void f(T t) { ... } |
| 306 | + |
| 307 | + |
| 308 | + void f(int* t) { ... } |
| 309 | + |
| 310 | + |
| 311 | + template <typename T> |
| 312 | + void f(T* t) { ... } |
| 313 | + \end{cppcode*} |
| 314 | + \columnbreak |
| 315 | + \begin{cppcode*}{} |
| 316 | + template <typename T> |
| 317 | + void f(T t) { ... } |
| 318 | + |
| 319 | + template <> |
| 320 | + void f<int*>(int* t) { ... } |
| 321 | + |
| 322 | + // part. spec. forbidden: |
| 323 | + template <typename T> |
| 324 | + void f<T*>(T* t) {...} |
| 325 | + \end{cppcode*} |
| 326 | + \end{multicols} |
| 327 | +\end{frame} |
| 328 | + |
| 329 | +\begin{frame}[fragile] |
| 330 | + \frametitlecpp[11]{Template argument deduction} |
| 331 | + \begin{block}{Disadvantages of specialization vs.\ overloading} |
| 332 | + \begin{itemize} |
| 333 | + \item Specialization always needs a primary template |
| 334 | + \begin{itemize} |
| 335 | + \item Sometimes this does not make sense |
| 336 | + \end{itemize} |
| 337 | + \item Partial specializations of function templates is forbidden |
| 338 | + \begin{itemize} |
| 339 | + \item So we need SFINAE workarounds or concepts |
| 340 | + \end{itemize} |
| 341 | + \end{itemize} |
| 342 | + \end{block} |
| 343 | + \small |
| 344 | + \begin{block}{Could you express this with specializations?} |
| 345 | + \begin{cppcode} |
| 346 | + template <typename T> |
| 347 | + void f(T* p) { ... } |
| 348 | + |
| 349 | + template <typename T> |
| 350 | + void f(std::unique_ptr<T> p) { ... } |
| 351 | + \end{cppcode} |
| 352 | + \end{block} |
| 353 | + \begin{goodpractice}{Specialization vs.\ overloading} |
| 354 | + Prefer overloading function templates over template specialization |
| 355 | + \end{goodpractice} |
| 356 | +\end{frame} |
| 357 | + |
169 | 358 | \begin{frame}[fragile]
|
170 | 359 | \frametitlecpp[17]{Class Template Argument Deduction (CTAD)}
|
171 | 360 | \begin{block}{CTAD}
|
|
238 | 427 | \end{block}
|
239 | 428 | \end{frame}
|
240 | 429 |
|
| 430 | +\end{advanced} |
| 431 | + |
241 | 432 | \begin{frame}[fragile]
|
242 | 433 | \frametitlecpp[98]{The full power of templates}
|
243 | 434 | \begin{exercise}{Templates}
|
|
0 commit comments