|
39 | 39 | \begin{itemize}
|
40 | 40 | \item \mintinline{cpp}{std::vector}, \mintinline{cpp}{std::array}, C arrays, ...
|
41 | 41 | \item not \mintinline{cpp}{std::list} or \mintinline{cpp}{std::deque} (no contiguous storage)
|
42 |
| - \item \mintinline{cpp}{span} should thus be preferred as function arguments |
| 42 | + \item \mintinline{cpp}{span} should thus be preferred as function argument |
43 | 43 | \end{itemize}
|
44 | 44 | \item Simply a pair (pointer, size), so cheap to copy
|
45 | 45 | \begin{itemize}
|
|
86 | 86 |
|
87 | 87 | \begin{frame}[fragile]
|
88 | 88 | \frametitlecpp[17]{std::optional}
|
89 |
| - \begin{block}{Manages an optional contained value} |
| 89 | + \begin{block}{Manages an optionally contained value} |
90 | 90 | \begin{itemize}
|
91 |
| - \item Contextually converts to bool telling if it contains something |
| 91 | + \item Contextually converts to bool, telling if it contains something |
92 | 92 | \item Has value semantics (Copy, Move, Compare, stack alloc.)
|
93 | 93 | \item Useful for the return value of a function that may fail
|
94 | 94 | \item Useful in place of pointers where value semantics are intuitive
|
95 | 95 | \end{itemize}
|
96 | 96 | \end{block}
|
97 |
| - \begin{exampleblock}{Code example} |
| 97 | + \begin{exampleblock}{} |
98 | 98 | \small
|
99 | 99 | \begin{cppcode*}{}
|
100 | 100 | std::optional<Phone> parse_phone(std::string_view in) {
|
101 | 101 | if (is_valid_phone(in))
|
102 |
| - return in; // equiv. to optional<Phone>(in); |
103 |
| - else |
104 |
| - return {}; // default constructs std::nullopt |
| 102 | + return in; // equiv. to optional<Phone>{in}; |
| 103 | + return {}; // or: return std::nullopt; (empty opt.) |
105 | 104 | }
|
106 |
| - auto v = parse_phone(...); |
107 |
| - if (v) { // alternatively v.is_valid() |
108 |
| - process_phone(v.value()); // *v is equivalent |
| 105 | + if (v) { // or: v.is_valid() |
| 106 | + process_phone(v.value()); // or: *v (unchecked) |
| 107 | + v->call(); // calls Phone::call() (unchecked) |
109 | 108 | }
|
| 109 | + v.reset(); assert(!v.has_value()); // or: v = {}; |
| 110 | + \end{cppcode*} |
| 111 | + \end{exampleblock} |
| 112 | +\end{frame} |
| 113 | + |
| 114 | +\begin{frame}[fragile] |
| 115 | + \frametitlecpp[17]{std::optional} |
| 116 | + \begin{exampleblock}{Code example} |
| 117 | + \small |
| 118 | + \begin{cppcode*}{} |
| 119 | + // address may be given for a person or not |
| 120 | + void processPerson(std::string_view name, |
| 121 | + std::optional<Address> address); |
| 122 | + Address addr = wonderland(); |
| 123 | + processPerson("Alice", std::move(addr)); |
| 124 | + |
| 125 | + // Every person has a name, but not always an address |
| 126 | + struct Person { |
| 127 | + std::string name; |
| 128 | + std::optional<Address> address; |
| 129 | + }; |
| 130 | + std::vector<Person> ps = ...; |
| 131 | + std::sort(ps.begin(), ps.end(), |
| 132 | + [](const Person& a, const Person& b) { |
| 133 | + return a.address < b.address; |
| 134 | + }); // sorts by address, persons w/o address at front |
110 | 135 | \end{cppcode*}
|
111 | 136 | \end{exampleblock}
|
112 | 137 | \end{frame}
|
|
124 | 149 |
|
125 | 150 | \begin{frame}[fragile]
|
126 | 151 | \frametitlecpp[17]{std::variant}
|
127 |
| - \begin{block}{a type-safe union} |
| 152 | + \begin{block}{A type-safe union} |
128 | 153 | \begin{itemize}
|
129 | 154 | \item Allows the variable to hold any of the given types
|
130 | 155 | \item \mintinline{cpp}{std::get} reads the value of the variant
|
131 | 156 | \item and throws \mintinline{cpp}{std::bad_variant_access} for bad accesses
|
132 |
| - \item Makes it easy to implement visitor pattern |
| 157 | + \item Currently held alternative can be probed |
133 | 158 | \end{itemize}
|
134 | 159 | \end{block}
|
135 | 160 | \begin{exampleblock}{Code example}
|
|
140 | 165 | try {
|
141 | 166 | float val = std::get<float>(opt) // will throw
|
142 | 167 | } catch (std::bad_variant_access const& ex) {...}
|
143 |
| - |
144 |
| - // Or check the type before accessing it |
145 | 168 | if (std::holds_alternative<float>(opt))
|
146 | 169 | std::cout << std::get<float>(opt);
|
| 170 | + if (const float* v = std::get_if<float>(opt)) { ... } |
| 171 | + const int current_alternative = opt.index(); // == 0 |
147 | 172 | \end{cppcode*}
|
148 | 173 | \end{exampleblock}
|
149 | 174 |
|
150 | 175 | \end{frame}
|
151 | 176 |
|
152 | 177 | \begin{frame}[fragile]
|
153 | 178 | \frametitlecpp[17]{std::variant and the visitor pattern}
|
154 |
| - \begin{block}{std::visit} |
| 179 | + \begin{block}{\texttt{std::visit}} |
155 | 180 | \begin{itemize}
|
156 |
| - \item Applies a ``visitor'' to given variant |
157 |
| - \item A visitor is a callable able to handle the different types |
| 181 | + \item Applies a ``visitor'' to a given variant |
| 182 | + \begin{itemize} |
| 183 | + \item A visitor is a callable able to handle all different types |
| 184 | + \item Must return \mintinline{cpp}{void} or the same type for all overloads |
| 185 | + \end{itemize} |
158 | 186 | \end{itemize}
|
159 | 187 | \end{block}
|
160 | 188 | \begin{exampleblock}{Practically}
|
161 | 189 | \small
|
162 | 190 | \begin{cppcode*}{gobble=2}
|
163 | 191 | struct Visitor {
|
164 |
| - void operator() (int i) { std::cout << "i32:" << i;} |
165 |
| - void operator() (float f) { std::cout << "f32:" << f;} |
166 |
| - void operator() (std::string s) { std::cout << s;} |
| 192 | + auto operator()(int i) {return "i:"+std::to_string(i);} |
| 193 | + auto operator()(float f) {return "f:"+std::to_string(f);} |
| 194 | + auto operator()(const std::string& s) { return "s:"+s;} |
167 | 195 | template <typename T>
|
168 |
| - void operator() (T t) { return std::cout << "other"; } |
| 196 | + auto operator()(const T& t) { return std::string{"?"}; } |
169 | 197 | };
|
170 | 198 | void print(std::variant<int, float, std::string, char> v) {
|
171 |
| - std::cout << std::visit(Visitor{}, v) << "\n; |
| 199 | + std::cout << std::visit(Visitor{}, v) << '\n'; |
172 | 200 | }
|
173 | 201 | print(100); print(42.0f); print("example"); print('A');
|
174 | 202 | \end{cppcode*}
|
|
220 | 248 | \item Allows a variable to hold any type (say bye to \mintinline{cpp}{void*})
|
221 | 249 | \item \mintinline{cpp}{std::any_cast} reads the internal value
|
222 | 250 | \item and throws \mintinline{cpp}{std::bad_any_cast} for bad accesses
|
223 |
| - \item \mintinline{cpp}{any_cast} will only match concrete types, ignoring inheritance |
| 251 | + \item \mintinline{cpp}{std::any_cast} only matches types 1:1, ignoring inheritance |
224 | 252 | \end{itemize}
|
225 | 253 | \end{block}
|
226 | 254 | \begin{exampleblock}{Code example}
|
|
232 | 260 | try {
|
233 | 261 | int val = std::any_cast<int>(val); // will throw
|
234 | 262 | } catch (std::bad_any_cast const& ex) {...}
|
235 |
| - // Or check the type before accessing it |
236 |
| - if (val.type() == typeid(int)) |
| 263 | + if (val.type() == typeid(int)) // requires RTTI |
237 | 264 | std::cout << std::any_cast<int>(val);
|
| 265 | + val.reset(); assert(!val.has_value()); |
238 | 266 | \end{cppcode*}
|
239 | 267 | \end{exampleblock}
|
240 | 268 | \end{frame}
|
|
0 commit comments