]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright Louis Dionne 2013-2016 |
2 | // Distributed under the Boost Software License, Version 1.0. | |
3 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) | |
4 | ||
5 | /*! | |
6 | ||
7 | @mainpage User Manual | |
8 | ||
9 | @tableofcontents | |
10 | ||
11 | ||
12 | ||
13 | ||
14 | ||
15 | ||
16 | ||
17 | ||
18 | ||
19 | ||
20 | @section tutorial-description Description | |
21 | ||
22 | ------------------------------------------------------------------------------ | |
23 | Hana is a header-only library for C++ metaprogramming suited for computations | |
24 | on both types and values. The functionality it provides is a superset of what | |
25 | is provided by the well established [Boost.MPL][] and [Boost.Fusion][] | |
26 | libraries. By leveraging C++11/14 implementation techniques and idioms, | |
27 | Hana boasts faster compilation times and runtime performance on par or better | |
28 | than previous metaprogramming libraries, while noticeably increasing the level | |
29 | of expressiveness in the process. Hana is easy to extend in a ad-hoc manner | |
30 | and it provides out-of-the-box inter-operation with Boost.Fusion, Boost.MPL | |
31 | and the standard library. | |
32 | ||
33 | ||
34 | ||
35 | ||
36 | ||
37 | ||
38 | ||
39 | ||
40 | ||
41 | ||
42 | @section tutorial-installation Prerequisites and installation | |
43 | ||
44 | ------------------------------------------------------------------------------ | |
45 | Hana is a header-only library without external dependencies (not even the rest | |
46 | of Boost). Hence, using Hana in your own project is very easy. Basically, just | |
47 | add the `include/` directory to your compiler's header search path and you are | |
48 | done. However, if you want to cleanly install Hana on your system, you have a | |
49 | couple of options. First, you can install Boost 1.61.0 or later, since Hana is | |
50 | included in Boost starting with that release. If you do not want to install all | |
51 | of Boost, it is also possible to install Hana only. To do so, you can download | |
52 | the code from the official GitHub [repository][Hana.repository] and install the | |
53 | library manually by issuing the following commands from the root of the project | |
54 | (requires [CMake][]): | |
55 | ||
56 | @code{.sh} | |
57 | mkdir build && cd build | |
58 | cmake .. | |
59 | cmake --build . --target install | |
60 | @endcode | |
61 | ||
62 | This will install Hana to the default install-directory for your platform | |
63 | (`/usr/local` for Unix, `C:/Program Files` for Windows). If you want to | |
64 | install Hana in a custom location, you can use | |
65 | ||
66 | @code{.sh} | |
67 | cmake .. -DCMAKE_INSTALL_PREFIX=/custom/install/prefix | |
68 | @endcode | |
69 | ||
70 | @note | |
71 | - The manual installation will also install a `hana.pc` file for use | |
72 | with [pkg-config][]. | |
73 | ||
74 | - Do not install Hana as shown above if you already have an installation of | |
75 | Boost, because the new installation will overwrite the one that comes with | |
76 | Boost. | |
77 | ||
78 | If you use CMake in a project, you can use the provided [FindHana.cmake][Hana.findmodule] | |
79 | module to setup Hana as an external CMake project. The module also allows | |
80 | installing Hana locally to that project, without needing to install Hana on | |
81 | the system per the above instructions. Finally, if you want to contribute to | |
82 | Hana, you can see how to best setup your environment for development in the | |
83 | [README][Hana.hacking]. | |
84 | ||
85 | @subsection tutorial-installation-requirements Compiler requirements | |
86 | ||
87 | The library relies on a C++14 compiler and standard library, but nothing else | |
88 | is required. Here is a table of the current C++14 compilers/toolchains with | |
89 | comments regarding support for Hana: | |
90 | ||
91 | Compiler/Toolchain | Status | |
92 | ------------------ | ------ | |
93 | Clang >= 3.5.0 | Fully working; tested on each push to GitHub | |
94 | Xcode >= 6.3 | Fully working; tested on each push to GitHub | |
95 | GCC >= 6.0.0 | Fully working; tested on each push to GitHub | |
96 | ||
97 | More specifically, Hana requires a compiler/standard library supporting the | |
98 | following C++14 features (non-exhaustively): | |
99 | - Generic lambdas | |
100 | - Generalized `constexpr` | |
101 | - Variable templates | |
102 | - Automatically deduced return type | |
103 | - All the C++14 type traits from the `<type_traits>` header | |
104 | ||
105 | More information for specific platforms is available on [the wiki][Hana.wiki]. | |
106 | ||
107 | ||
108 | ||
109 | ||
110 | ||
111 | ||
112 | ||
113 | ||
114 | ||
115 | ||
116 | @section tutorial-support Support | |
117 | ||
118 | ------------------------------------------------------------------------------ | |
119 | ||
120 | If you have a problem, please review the [FAQ](@ref tutorial-rationales) and | |
121 | [the wiki][Hana.wiki]. Searching [the issues][Hana.issues] for your problem is | |
122 | also a good idea. If that doesn't help, feel free to chat with us in [Gitter][Hana.chat], | |
123 | or open a new issue. [StackOverflow][] with the [boost-hana][Hana.StackOverflow] | |
124 | tag is the preferred place to ask questions on usage. If you are encountering | |
125 | what you think is a bug, please open an issue. | |
126 | ||
127 | ||
128 | ||
129 | ||
130 | ||
131 | ||
132 | ||
133 | ||
134 | ||
135 | ||
136 | @section tutorial-introduction Introduction | |
137 | ||
138 | ------------------------------------------------------------------------------ | |
139 | When Boost.MPL first appeared, it provided C++ programmers with a huge relief | |
140 | by abstracting tons of template hackery behind a workable interface. This | |
141 | breakthrough greatly contributed to making C++ template metaprogramming more | |
142 | mainstream, and today the discipline is deeply rooted in many serious projects. | |
143 | Recently, C++11 and C++14 brought many major changes to the language, some of | |
144 | which make metaprogramming much easier, while others drastically widen the | |
145 | design space for libraries. A natural question then arises: is it still | |
146 | desirable to have abstractions for metaprogramming, and if so, which ones? | |
147 | After investigating different options like the [MPL11][], the answer eventually | |
148 | came by itself in the form of a library; Hana. The key insight to Hana is that | |
149 | the manipulation of types and values are nothing but two sides of the same | |
150 | coin. By unifying both concepts, metaprogramming becomes easier and new | |
151 | exciting possibilities open before us. | |
152 | ||
153 | ||
154 | @subsection tutorial-introduction-quadrants C++ computational quadrants | |
155 | ||
156 | But to really understand what is Hana all about, it is essential to understand | |
157 | the different types of computations in C++. We will focus our attention on | |
158 | four different kinds of computations, even though a finer grained separation | |
159 | would be possible. First, we have runtime computations, which are the usual | |
160 | computations we use in C++. In that world, we have runtime containers, | |
161 | runtime functions and runtime algorithms: | |
162 | ||
163 | @snippet example/tutorial/introduction.cpp runtime | |
164 | ||
165 | The usual toolbox for programming within this quadrant is the C++ standard | |
166 | library, which provides reusable algorithms and containers operating at | |
167 | runtime. Since C++11, a second kind of computation is possible: `constexpr` | |
168 | computations. There, we have `constexpr` containers, `constexpr` functions | |
169 | and `constexpr` algorithms: | |
170 | ||
171 | @code{cpp} | |
172 | constexpr int factorial(int n) { | |
173 | return n == 0 ? 1 : n * factorial(n - 1); | |
174 | } | |
175 | ||
176 | template <typename T, std::size_t N, typename F> | |
177 | constexpr std::array<std::result_of_t<F(T)>, N> | |
178 | transform(std::array<T, N> array, F f) { | |
179 | // ... | |
180 | } | |
181 | ||
182 | constexpr std::array<int, 4> ints{{1, 2, 3, 4}}; | |
183 | constexpr std::array<int, 4> facts = transform(ints, factorial); | |
184 | static_assert(facts == std::array<int, 4>{{1, 2, 6, 24}}, ""); | |
185 | @endcode | |
186 | ||
187 | @note | |
188 | For the above code to actually work, `std::array`'s `operator==` would have to | |
189 | be marked `constexpr`, which is not the case (even in C++14). | |
190 | ||
191 | Basically, a `constexpr` computation is different from a runtime computation | |
192 | in that it is simple enough to be evaluated (interpreted, really) by the | |
193 | compiler. In general, any function that does not perform anything too | |
194 | _unfriendly_ to the compiler's evaluator (like throwing or allocating memory) | |
195 | can be marked `constexpr` without any further change. This makes `constexpr` | |
196 | computations very similar to runtime computations, except `constexpr` | |
197 | computations are more restricted and they gain the ability to be evaluated | |
198 | at compile-time. Unfortunately, there is no commonly used toolbox for | |
199 | `constexpr`-programming, i.e. there is no widely adopted "standard library" | |
200 | for `constexpr` programming. However, the [Sprout][] library may be worth | |
201 | checking out for those with some interest in `constexpr` computations. | |
202 | ||
203 | The third kind of computations are heterogeneous computations. Heterogeneous | |
204 | computations differ from normal computations in that instead of having | |
205 | containers holding homogeneous objects (all objects having the same type), | |
206 | the containers may hold objects with different types. Furthermore, functions | |
207 | in this quadrant of computation are _heterogeneous_ functions, which is a | |
208 | complicated way of talking about template functions. Similarly, we have | |
209 | heterogeneous algorithms that manipulate heterogeneous containers and | |
210 | functions: | |
211 | ||
212 | @snippet example/tutorial/introduction.cpp heterogeneous | |
213 | ||
214 | If manipulating heterogeneous containers seems overly weird to you, just think | |
215 | of it as glorified `std::tuple` manipulation. In a C++03 world, the go-to | |
216 | library for doing this kind of computation is [Boost.Fusion][], which provides | |
217 | several data structures and algorithms to manipulate heterogeneous collections | |
218 | of data. The fourth and last quadrant of computation that we'll be considering | |
219 | here is the quadrant of type-level computations. In this quadrant, we have | |
220 | type-level containers, type-level functions (usually called metafunctions) | |
221 | and type-level algorithms. Here, everything operates on types: containers hold | |
222 | types and metafunctions take types as arguments and return types as results. | |
223 | ||
224 | @snippet example/tutorial/introduction.cpp type-level | |
225 | ||
226 | The realm of type-level computations has been explored quite extensively, and | |
227 | the de-facto solution for type-level computations in C++03 is a library named | |
228 | [Boost.MPL][], which provides type-level containers and algorithms. For | |
229 | low-level type transformations, the metafunctions provided by the | |
230 | `<type_traits>` standard header can also be used since C++11. | |
231 | ||
232 | ||
233 | @subsection tutorial-quadrants-about What is this library about? | |
234 | ||
235 | So all is good, but what is this library actually about? Now that we have set | |
236 | the table by clarifying the kinds of computations available to us in C++, the | |
237 | answer might strike you as very simple. __The purpose of Hana is to merge the | |
238 | 3rd and the 4th quadrants of computation__. More specifically, Hana is a | |
239 | (long-winded) constructive proof that heterogeneous computations are strictly | |
240 | more powerful than type-level computations, and that we can therefore express | |
241 | any type-level computation by an equivalent heterogeneous computation. This | |
242 | construction is done in two steps. First, Hana is a fully featured library of | |
243 | heterogeneous algorithms and containers, a bit like a modernized Boost.Fusion. | |
244 | Secondly, Hana provides a way of translating any type-level computation into its | |
245 | equivalent heterogeneous computation and back, which allows the full machinery | |
246 | of heterogeneous computations to be reused for type-level computations without | |
247 | any code duplication. Of course, the biggest advantage of this unification is | |
248 | seen by the user, as you will witness by yourself. | |
249 | ||
250 | ||
251 | ||
252 | ||
253 | ||
254 | ||
255 | ||
256 | ||
257 | ||
258 | ||
259 | @section tutorial-quickstart Quick start | |
260 | ||
261 | ------------------------------------------------------------------------------ | |
262 | The goal of this section is to introduce the main concepts of the library | |
263 | from a very high level and at a fairly rapid pace; don't worry if you don't | |
264 | understand everything that's about to be thrown at you. However, this tutorial | |
265 | assumes the reader is already at least _familiar_ with basic metaprogramming | |
266 | and the [C++14 standard][C++14]. First, let's include the library: | |
267 | ||
268 | @snippet example/tutorial/quickstart.cpp includes | |
269 | ||
270 | Unless specified otherwise, the documentation assumes the above lines to be | |
271 | present before examples and code snippets. Also note that finer grained | |
272 | headers are provided and will be explained in the [Header organization] | |
273 | (@ref tutorial-header_organization) section. For the purpose of the | |
274 | quickstart, let's now include some additional headers and define some | |
275 | lovely animal types that we'll need below: | |
276 | ||
277 | @snippet example/tutorial/quickstart.cpp additional_setup | |
278 | ||
279 | If you are reading this documentation, chances are you already know | |
280 | `std::tuple` and `std::make_tuple`. Hana provides its own tuple and | |
281 | `make_tuple`: | |
282 | ||
283 | @snippet example/tutorial/quickstart.cpp animals | |
284 | ||
285 | This creates a tuple, which is like an array, except that it can hold elements | |
286 | with different types. Containers that can hold elements with different types | |
287 | such as this are called heterogeneous containers. While the standard library | |
288 | provides very few operations to manipulate `std::tuple`s, Hana provides several | |
289 | operations and algorithms to manipulate its own tuples: | |
290 | ||
291 | @snippet example/tutorial/quickstart.cpp algorithms | |
292 | ||
293 | @note | |
294 | `1_c` is a [C++14 user-defined literal][C++14.udl] creating a | |
295 | [compile-time number](@ref tutorial-integral). These user-defined | |
296 | literals are contained in the `boost::hana::literals` namespace, | |
297 | hence the `using` directive. | |
298 | ||
299 | Notice how we pass a [C++14 generic lambda][C++14.glambda] to `transform`; | |
300 | this is required because the lambda will first be called with a `Fish`, then | |
301 | a `Cat`, and finally a `Dog`, which all have different types. Hana provides | |
302 | most of the algorithms provided by the C++ standard library, except they work | |
303 | on tuples and related heterogeneous containers instead of `std::vector` & | |
304 | friends. In addition to working with heterogeneous values, Hana makes it | |
305 | possible to perform type-level computations with a natural syntax, all at | |
306 | compile-time and with no overhead whatsoever. This compiles and does just | |
307 | what you would expect: | |
308 | ||
309 | @snippet example/tutorial/quickstart.cpp type-level | |
310 | ||
311 | @note | |
312 | `type_c<...>` is not a type! It is a [C++14 variable template][C++14.vtemplate] | |
313 | yielding an object representing a type for Hana. This is explained in the | |
314 | section on [type computations](@ref tutorial-type). | |
315 | ||
316 | In addition to heterogeneous and compile-time sequences, Hana provides several | |
317 | features to make your metaprogramming nightmares a thing of the past. For | |
318 | example, one can check for the existence of a struct member with one easy | |
319 | line instead of relying on [clunky SFINAE hacks][SO.sfinae]: | |
320 | ||
321 | @snippet example/tutorial/quickstart.cpp has_name | |
322 | ||
323 | Writing a serialization library? Stop crying, we've got you covered. | |
324 | Reflection can be added to user-defined types very easily. This allows | |
325 | iterating over the members of a user-defined type, querying members with | |
326 | a programmatic interface and much more, without any runtime overhead: | |
327 | ||
328 | @snippet example/tutorial/quickstart.cpp serialization | |
329 | ||
330 | That's cool, but I can already hear you complaining about incomprehensible | |
331 | error messages. However, it turns out Hana was built for humans, not | |
332 | professional template metaprogrammers, and this shows. Let's intentionally | |
333 | screw up and see what kind of mess is thrown at us. First, the mistake: | |
334 | ||
335 | @snippet example/tutorial/quickstart.cpp screw_up | |
336 | ||
337 | Now, the punishment: | |
338 | ||
339 | @code{cpp} | |
340 | error: static_assert failed "hana::for_each(xs, f) requires 'xs' to be Foldable" | |
341 | static_assert(Foldable<S>::value, | |
342 | ^ ~~~~~~~~~~~~~~~~~~ | |
343 | note: in instantiation of function template specialization | |
344 | 'boost::hana::for_each_t::operator()< | |
345 | std::__1::basic_ostream<char> &, (lambda at [snip])>' requested here | |
346 | hana::for_each(os, [&](auto member) { | |
347 | ^ | |
348 | note: in instantiation of function template specialization | |
349 | 'main()::(anonymous class)::operator()<Person>' requested here | |
350 | serialize(std::cout, john); | |
351 | ^ | |
352 | @endcode | |
353 | ||
354 | Not that bad, right? However, since small examples are very good to show off | |
355 | without actually doing something useful, let's examine a real world example. | |
356 | ||
357 | ||
358 | @subsection tutorial-quickstart-any A real world example | |
359 | ||
360 | In this section our goal will be to implement a kind of `switch` statement | |
361 | able to process `boost::any`s. Given a `boost::any`, the goal is to dispatch | |
362 | to the function associated to the dynamic type of the `any`: | |
363 | ||
364 | @snippet example/tutorial/quickstart.switchAny.cpp usage | |
365 | ||
366 | @note | |
367 | In the documentation, we will often use the `s` suffix on string literals to | |
368 | create `std::string`s without syntactic overhead. This is a standard-defined | |
369 | [C++14 user-defined literal][C++14.udl]. | |
370 | ||
371 | Since the any holds a `char`, the second function is called with the `char` | |
372 | inside it. If the `any` had held an `int` instead, the first function would | |
373 | have been called with the `int` inside it. When the dynamic type of the `any` | |
374 | does not match any of the covered cases, the `%default_` function is called | |
375 | instead. Finally, the result of the `switch` is the result of calling the | |
376 | function associated to the `any`'s dynamic type. The type of that result is | |
377 | inferred to be the common type of the result of all the provided functions: | |
378 | ||
379 | @snippet example/tutorial/quickstart.switchAny.cpp result_inference | |
380 | ||
381 | We'll now look at how this utility can be implemented using Hana. The first | |
382 | step is to associate each type to a function. To do so, we represent each | |
383 | `case_` as a `hana::pair` whose first element is a type and whose second | |
384 | element is a function. Furthermore, we (arbitrarily) decide to represent the | |
385 | `%default_` case as a `hana::pair` mapping a dummy type to a function: | |
386 | ||
387 | @snippet example/tutorial/quickstart.switchAny.cpp cases | |
388 | ||
389 | To provide the interface we showed above, `switch_` will have to return a | |
390 | function taking the cases. In other words, `switch_(a)` must be a function | |
391 | taking any number of cases (which are `hana::pair`s), and performing the logic | |
392 | to dispatch `a` to the right function. This can easily be achieved by having | |
393 | `switch_` return a C++14 generic lambda: | |
394 | ||
395 | @code{cpp} | |
396 | template <typename Any> | |
397 | auto switch_(Any& a) { | |
398 | return [&a](auto ...cases_) { | |
399 | // ... | |
400 | }; | |
401 | } | |
402 | @endcode | |
403 | ||
404 | However, since parameter packs are not very flexible, we'll put the cases | |
405 | into a tuple so we can manipulate them: | |
406 | ||
407 | @code{cpp} | |
408 | template <typename Any> | |
409 | auto switch_(Any& a) { | |
410 | return [&a](auto ...cases_) { | |
411 | auto cases = hana::make_tuple(cases_...); | |
412 | // ... | |
413 | }; | |
414 | } | |
415 | @endcode | |
416 | ||
417 | Notice how the `auto` keyword is used when defining `cases`; it is often | |
418 | easier to let the compiler deduce the type of the tuple and use `make_tuple` | |
419 | instead of working out the types manually. The next step is to separate the | |
420 | default case from the rest of the cases. This is where things start to get | |
421 | interesting. To do so, we use Hana's `find_if` algorithm, which works a bit | |
422 | like `std::find_if`: | |
423 | ||
424 | @code{cpp} | |
425 | template <typename Any> | |
426 | auto switch_(Any& a) { | |
427 | return [&a](auto ...cases_) { | |
428 | auto cases = hana::make_tuple(cases_...); | |
429 | ||
430 | auto default_ = hana::find_if(cases, [](auto const& c) { | |
431 | return hana::first(c) == hana::type_c<default_t>; | |
432 | }); | |
433 | ||
434 | // ... | |
435 | }; | |
436 | } | |
437 | @endcode | |
438 | ||
439 | `find_if` takes a `tuple` and a predicate, and returns the first element of | |
440 | the tuple which satisfies the predicate. The result is returned as a | |
441 | `hana::optional`, which is very similar to a `std::optional`, except | |
442 | whether that optional value is empty or not is known at compile-time. If the | |
443 | predicate is not satisfied for any element of the `tuple`, `find_if` returns | |
444 | `nothing` (an empty value). Otherwise, it returns `just(x)` (a non-empty value), | |
445 | where `x` is the first element satisfying the predicate. Unlike predicates | |
446 | used in STL algorithms, the predicate used here must be generic because the | |
447 | tuple's elements are heterogeneous. Furthermore, that predicate must return | |
448 | what Hana calls an `IntegralConstant`, which means that the predicate's result | |
449 | must be known at compile-time. These details are explained in the section on | |
450 | [cross-phase algorithms](@ref tutorial-algorithms-cross_phase). Inside the | |
451 | predicate, we simply compare the type of the case's first element to | |
452 | `type_c<default_t>`. If you recall that we were using `hana::pair`s to encode | |
453 | cases, this simply means that we're finding the default case among all of the | |
454 | provided cases. But what if no default case was provided? We should fail at | |
455 | compile-time, of course! | |
456 | ||
457 | @code{cpp} | |
458 | template <typename Any> | |
459 | auto switch_(Any& a) { | |
460 | return [&a](auto ...cases_) { | |
461 | auto cases = hana::make_tuple(cases_...); | |
462 | ||
463 | auto default_ = hana::find_if(cases, [](auto const& c) { | |
464 | return hana::first(c) == hana::type_c<default_t>; | |
465 | }); | |
466 | static_assert(default_ != hana::nothing, | |
467 | "switch is missing a default_ case"); | |
468 | ||
469 | // ... | |
470 | }; | |
471 | } | |
472 | @endcode | |
473 | ||
474 | Notice how we can use `static_assert` on the result of the comparison with | |
475 | `nothing`, even though `%default_` is a non-`constexpr` object? Boldly, Hana | |
476 | makes sure that no information that's known at compile-time is lost to the | |
477 | runtime, which is clearly the case of the presence of a `%default_` case. | |
478 | The next step is to gather the set of non-default cases. To achieve this, we | |
479 | use the `filter` algorithm, which keeps only the elements of the sequence | |
480 | satisfying the predicate: | |
481 | ||
482 | @code{cpp} | |
483 | template <typename Any> | |
484 | auto switch_(Any& a) { | |
485 | return [&a](auto ...cases_) { | |
486 | auto cases = hana::make_tuple(cases_...); | |
487 | ||
488 | auto default_ = hana::find_if(cases, [](auto const& c) { | |
489 | return hana::first(c) == hana::type_c<default_t>; | |
490 | }); | |
491 | static_assert(default_ != hana::nothing, | |
492 | "switch is missing a default_ case"); | |
493 | ||
494 | auto rest = hana::filter(cases, [](auto const& c) { | |
495 | return hana::first(c) != hana::type_c<default_t>; | |
496 | }); | |
497 | ||
498 | // ... | |
499 | }; | |
500 | } | |
501 | @endcode | |
502 | ||
503 | The next step is to find the first case matching the dynamic type of the `any`, | |
504 | and then call the function associated to that case. The simplest way to do this | |
505 | is to use classic recursion with variadic parameter packs. Of course, we could | |
506 | probably intertwine Hana algorithms in a convoluted way to achieve this, but | |
507 | sometimes the best way to do something is to write it from scratch using basic | |
508 | techniques. To do so, we'll call an implementation function with the contents | |
509 | of the `rest` tuple by using the `unpack` function: | |
510 | ||
511 | @snippet example/tutorial/quickstart.switchAny.cpp switch_ | |
512 | ||
513 | `unpack` takes a `tuple` and a function, and calls the function with the content | |
514 | of the `tuple` as arguments. The result of `unpack` is the result of calling that | |
515 | function. In our case, the function is a generic lambda which in turn calls the | |
516 | `process` function. Our reason for using `unpack` here was to turn the `rest` | |
517 | tuple into a parameter pack of arguments, which are easier to process recursively | |
518 | than tuples. Before we move on to the `process` function, it is worthwhile to | |
519 | explain what `second(*%default_)` is all about. As we explained earlier, | |
520 | `%default_` is an optional value. Like `std::optional`, this optional value | |
521 | overloads the dereference operator (and the arrow operator) to allow accessing | |
522 | the value inside the `optional`. If the optional is empty (`nothing`), a | |
523 | compile-time error is triggered. Since we know `%default_` is not empty (we | |
524 | checked that just above), what we're doing is simply pass the function | |
525 | associated to the default case to the `process` function. We're now ready | |
526 | for the final step, which is the implementation of the `process` function: | |
527 | ||
528 | @snippet example/tutorial/quickstart.switchAny.cpp process | |
529 | ||
530 | There are two overloads of this function: an overload for when there is at least | |
531 | one case to process, and the base case overload for when there's only the default | |
532 | case. As we would expect, the base case simply calls the default function and | |
533 | returns that result. The other overload is slightly more interesting. First, | |
534 | we retrieve the type associated to that case and store it in `T`. This | |
535 | `decltype(...)::%type` dance might seem convoluted, but it is actually quite | |
536 | simple. Roughly speaking, this takes a type represented as an object (a `type<T>`) | |
537 | and pulls it back down to the type level (a `T`). The details are explained in | |
538 | the section on [type-level computations](@ref tutorial-type). Then, we compare | |
539 | whether the dynamic type of the `any` matches this case, and if so we call the | |
540 | function associated to this case with the `any` casted to the proper type. | |
541 | Otherwise, we simply call `process` recursively with the rest of the cases. | |
542 | Pretty simple, wasn't it? Here's the final solution: | |
543 | ||
544 | @snippet example/tutorial/quickstart.switchAny.cpp full | |
545 | ||
546 | That's it for the quick start! This example only introduced a couple of useful | |
547 | algorithms (`find_if`, `filter`, `unpack`) and heterogeneous containers | |
548 | (`tuple`, `optional`), but rest assured that there is much more. The next | |
549 | sections of the tutorial gradually introduce general concepts pertaining to | |
550 | Hana in a friendly way, but you may use the following cheatsheet for quick | |
551 | reference if you want to start coding right away. This cheatsheet contains | |
552 | the most frequently used algorithms and containers, along with a short | |
553 | description of what each of them does. | |
554 | ||
555 | ||
556 | @subsection tutorial-quickstart-cheatsheet Cheatsheet | |
557 | ||
558 | ### Remarks | |
559 | - Most algorithms work on both types and values (see the section on | |
560 | [type computations](@ref tutorial-type)) | |
561 | - Algorithms always return their result as a new container; no in-place | |
562 | mutation is ever performed (see the section on [algorithms] | |
563 | (@ref tutorial-algorithms)) | |
564 | - All algorithms are `constexpr` function objects | |
565 | ||
566 | ||
567 | container | description | |
568 | :----------------- | :---------- | |
569 | <code>[tuple](@ref boost::hana::tuple)</code> | General purpose index-based heterogeneous sequence with a fixed length. Use this as a `std::vector` for heterogeneous objects. | |
570 | <code>[optional](@ref boost::hana::optional)</code> | Represents an optional value, i.e. a value that can be empty. This is a bit like `std::optional`, except that the emptiness is known at compile-time. | |
571 | <code>[map](@ref boost::hana::map)</code> | Unordered associative array mapping (unique) compile-time entities to arbitrary objects. This is like `std::unordered_map` for heterogeneous objects. | |
572 | <code>[set](@ref boost::hana::set)</code> | Unordered container holding unique keys that must be compile-time entities. This is like `std::unordered_set` for heterogeneous objects. | |
573 | <code>[range](@ref boost::hana::range)</code> | Represents an interval of compile-time numbers. This is like `std::integer_sequence`, but better. | |
574 | <code>[pair](@ref boost::hana::pair)</code> | Container holding two heterogeneous objects. Like `std::pair`, but compresses the storage of empty types. | |
575 | <code>[string](@ref boost::hana::string)</code> | Compile-time string. | |
576 | <code>[type](@ref boost::hana::type)</code> | Container representing a C++ type. This is the root of the unification between types and values, and is of interest for MPL-style computations (type-level computations). | |
577 | <code>[integral_constant](@ref boost::hana::integral_constant)</code> | Represents a compile-time number. This is very similar to `std::integral_constant`, except that `hana::integral_constant` also defines operators and more syntactic sugar. | |
578 | <code>[lazy](@ref boost::hana::lazy)</code> | Encapsulates a lazy value or computation. | |
579 | <code>[basic_tuple](@ref boost::hana::basic_tuple)</code> | Stripped-down version of `hana::tuple`. Not standards conforming, but more compile-time efficient. | |
580 | ||
581 | ||
582 | function | description | |
583 | :------------------------------------------ | :---------- | |
584 | <code>[adjust](@ref ::boost::hana::adjust)(sequence, value, f)</code> | Apply a function to each element of a sequence that compares equal to some value and return the result. | |
585 | <code>[adjust_if](@ref ::boost::hana::adjust_if)(sequence, predicate, f)</code> | Apply a function to each element of a sequence satisfying some predicate and return the result. | |
586 | <code>{[all](@ref ::boost::hana::all),[any](@ref ::boost::hana::any),[none](@ref ::boost::hana::none)}(sequence)</code> | Returns whether all/any/none of the elements of a sequence are true-valued. | |
587 | <code>{[all](@ref ::boost::hana::all_of),[any](@ref ::boost::hana::any_of),[none](@ref ::boost::hana::none_of)}_of(sequence, predicate)</code> | Returns whether all/any/none of the elements of the sequence satisfy some predicate. | |
588 | <code>[append](@ref ::boost::hana::append)(sequence, value)</code> | Append an element to a sequence. | |
589 | <code>[at](@ref ::boost::hana::at)(sequence, index)</code> | Returns the n-th element of a sequence. The index must be an `IntegralConstant`. | |
590 | <code>[back](@ref ::boost::hana::back)(sequence)</code> | Returns the last element of a non-empty sequence. | |
591 | <code>[concat](@ref ::boost::hana::concat)(sequence1, sequence2)</code> | Concatenate two sequences. | |
592 | <code>[contains](@ref ::boost::hana::contains)(sequence, value)</code> | Returns whether a sequence contains the given object. | |
593 | <code>[count](@ref ::boost::hana::count)(sequence, value)</code> | Returns the number of elements that compare equal to the given value. | |
594 | <code>[count_if](@ref ::boost::hana::count_if)(sequence, predicate)</code> | Returns the number of elements that satisfy the predicate. | |
595 | <code>[drop_front](@ref ::boost::hana::drop_front)(sequence[, n])</code> | Drop the first `n` elements from a sequence, or the whole sequence if `length(sequence) <= n`. `n` must be an `IntegralConstant`. When not provided, `n` defaults to 1. | |
596 | <code>[drop_front_exactly](@ref ::boost::hana::drop_front_exactly)(sequence[, n])</code> | Drop the first `n` elements from a sequence. `n` must be an `IntegralConstant` and the sequence must have at least `n` elements. When not provided, `n` defaults to 1. | |
597 | <code>[drop_back](@ref ::boost::hana::drop_back)(sequence[, n])</code> | Drop the last `n` elements from a sequence, or the whole sequence if `length(sequence) <= n`. `n` must be an `IntegralConstant`. When not provided, `n` defaults to 1. | |
598 | <code>[drop_while](@ref ::boost::hana::drop_while)(sequence, predicate)</code> | Drops elements from a sequence while a predicate is satisfied. The predicate must return an `IntegralConstant`. | |
599 | <code>[fill](@ref ::boost::hana::fill)(sequence, value)</code> | Replace all the elements of a sequence with some value. | |
600 | <code>[filter](@ref ::boost::hana::filter)(sequence, predicate)</code> | Remove all the elements that do not satisfy a predicate. The predicate must return an `IntegralConstant`. | |
601 | <code>[find](@ref ::boost::hana::find)(sequence, value)</code> | Find the first element of a sequence which compares equal to some value and return `just` it, or return `nothing`. See `hana::optional`. | |
602 | <code>[find_if](@ref ::boost::hana::find_if)(sequence, predicate)</code> | Find the first element of a sequence satisfying the predicate and return `just` it, or return `nothing`. See `hana::optional`. | |
603 | <code>[flatten](@ref ::boost::hana::flatten)(sequence)</code> | Flatten a sequence of sequences, a bit like `std::tuple_cat`. | |
604 | <code>[fold_left](@ref ::boost::hana::fold_left)(sequence[, state], f)</code> | Accumulates the elements of a sequence from the left, optionally with a provided initial state. | |
605 | <code>[fold_right](@ref ::boost::hana::fold_right)(sequence[, state], f)</code> | Accumulates the elements of a sequence from the right, optionally with a provided initial state. | |
606 | <code>[fold](@ref ::boost::hana::fold)(sequence[, state], f)</code> | Equivalent to `fold_left`; provided for consistency with Boost.MPL and Boost.Fusion. | |
607 | <code>[for_each](@ref ::boost::hana::for_each)(sequence, f)</code> | Call a function on each element of a sequence. Returns `void`. | |
608 | <code>[front](@ref ::boost::hana::front)(sequence)</code> | Returns the first element of a non-empty sequence. | |
609 | <code>[group](@ref ::boost::hana::group)(sequence[, predicate])</code> | %Group adjacent elements of a sequence which all satisfy (or all do not satisfy) some predicate. The predicate defaults to equality, in which case the elements must be `Comparable`. | |
610 | <code>[insert](@ref ::boost::hana::insert)(sequence, index, element)</code> | Insert an element at a given index. The index must be an `IntegralConstant`. | |
611 | <code>[insert_range](@ref ::boost::hana::insert_range)(sequence, index, elements)</code> | Insert a sequence of elements at a given index. The index must be an `IntegralConstant`. | |
612 | <code>[is_empty](@ref ::boost::hana::is_empty)(sequence)</code> | Returns whether a sequence is empty as an `IntegralConstant`. | |
613 | <code>[length](@ref ::boost::hana::length)(sequence)</code> | Returns the length of a sequence as an `IntegralConstant`. | |
614 | <code>[lexicographical_compare](@ref ::boost::hana::lexicographical_compare)(sequence1, sequence2[, predicate])</code> | Performs a lexicographical comparison of two sequences, optionally with a custom predicate, by default with `hana::less`. | |
615 | <code>[maximum](@ref ::boost::hana::maximum)(sequence[, predicate])</code> | Returns the greatest element of a sequence, optionally according to a predicate. The elements must be `Orderable` if no predicate is provided. | |
616 | <code>[minimum](@ref ::boost::hana::minimum)(sequence[, predicate])</code> | Returns the smallest element of a sequence, optionally according to a predicate. The elements must be `Orderable` if no predicate is provided. | |
617 | <code>[partition](@ref ::boost::hana::partition)(sequence, predicate)</code> | Partition a sequence into a pair of elements that satisfy some predicate, and elements that do not satisfy it. | |
618 | <code>[prepend](@ref ::boost::hana::prepend)(sequence, value)</code> | Prepend an element to a sequence. | |
619 | <code>[remove](@ref ::boost::hana::remove)(sequence, value)</code> | Remove all the elements that are equal to a given value. | |
620 | <code>[remove_at](@ref ::boost::hana::remove_at)(sequence, index)</code> | Remove the element at the given index. The index must be an `IntegralConstant`. | |
621 | <code>[remove_if](@ref ::boost::hana::remove_if)(sequence, predicate)</code> | Remove all the elements that satisfy a predicate. The predicate must return an `IntegralConstant`. | |
622 | <code>[remove_range](@ref ::boost::hana::remove_range)(sequence, from, to)</code> | Remove the elements at indices in the given `[from, to)` half-open interval. The indices must be `IntegralConstant`s. | |
623 | <code>[replace](@ref ::boost::hana::replace)(sequence, oldval, newval)</code> | Replace the elements of a sequence that compare equal to some value by some other value. | |
624 | <code>[replace_if](@ref ::boost::hana::replace_if)(sequence, predicate, newval)</code> | Replace the elements of a sequence that satisfy some predicate by some value. | |
625 | <code>[reverse](@ref ::boost::hana::reverse)(sequence)</code> | Reverse the order of the elements in a sequence. | |
626 | <code>[reverse_fold](@ref ::boost::hana::reverse_fold)(sequence[, state], f)</code> | Equivalent to `fold_right`; provided for consistency with Boost.MPL and Boost.Fusion. | |
627 | <code>[size](@ref ::boost::hana::size)(sequence)</code> | Equivalent to `length`; provided for consistency with the C++ standard library. | |
628 | <code>[slice](@ref ::boost::hana::slice)(sequence, indices)</code> | Returns a new sequence containing the elements at the given indices of the original sequence. | |
629 | <code>[slice_c](@ref ::boost::hana::slice_c)<from, to>(sequence)</code> | Returns a new sequence containing the elements at indices contained in `[from, to)` of the original sequence. | |
630 | <code>[sort](@ref ::boost::hana::sort)(sequence[, predicate])</code> | Sort (stably) the elements of a sequence, optionally according to a predicate. The elements must be `Orderable` if no predicate is provided. | |
631 | <code>[take_back](@ref ::boost::hana::take_back)(sequence, number)</code> | Take the last n elements of a sequence, or the whole sequence if `length(sequence) <= n`. n must be an `IntegralConstant`. | |
632 | <code>[take_front](@ref ::boost::hana::take_front)(sequence, number)</code> | Take the first n elements of a sequence, or the whole sequence if `length(sequence) <= n`. n must be an `IntegralConstant`. | |
633 | <code>[take_while](@ref ::boost::hana::take_while)(sequence, predicate)</code> | Take elements of a sequence while some predicate is satisfied, and return that. | |
634 | <code>[transform](@ref ::boost::hana::transform)(sequence, f)</code> | Apply a function to each element of a sequence and return the result. | |
635 | <code>[unique](@ref ::boost::hana::unique)(sequence[, predicate])</code> | Removes all consecutive duplicates from a sequence. The predicate defaults to equality, in which case the elements must be `Comparable`. | |
636 | <code>[unpack](@ref ::boost::hana::unpack)(sequence, f)</code> | Calls a function with the contents of a sequence. Equivalent to `f(x1, ..., xN)`. | |
637 | <code>[zip](@ref ::boost::hana::zip)(s1, ..., sN)</code> | Zip `N` sequences into a sequence of tuples. All the sequences must have the same length. | |
638 | <code>[zip_shortest](@ref ::boost::hana::zip_shortest)(s1, ..., sN)</code> | Zip `N` sequences into a sequence of tuples. The resulting sequence has the length of the shortest input sequence. | |
639 | <code>[zip_with](@ref ::boost::hana::zip_with)(f, s1, ..., sN)</code> | Zip `N` sequences with a `N`-ary function. All the sequences must have the same length. | |
640 | <code>[zip_shortest_with](@ref ::boost::hana::zip_shortest_with)(f, s1, ..., sN)</code> | Zip `N` sequences with a `N`-ary function. The resulting sequence has the length of the shortest input sequence. | |
641 | ||
642 | ||
643 | ||
644 | ||
645 | ||
646 | ||
647 | ||
648 | ||
649 | ||
650 | ||
651 | @section tutorial-assert Assertions | |
652 | ||
653 | ------------------------------------------------------------------------------ | |
654 | In the rest of this tutorial, you will come across code snippets where different | |
655 | kinds of assertions like `BOOST_HANA_RUNTIME_CHECK` and `BOOST_HANA_CONSTANT_CHECK` | |
656 | are used. Like any sensible `assert` macro, they basically check that the | |
657 | condition they are given is satisfied. However, in the context of heterogeneous | |
658 | programming, some informations are known at compile-time, while others are known | |
659 | only at runtime. The exact type of assertion that's used in a context tells you | |
660 | whether the condition that's asserted upon can be known at compile-time or if it | |
661 | must be computed at runtime, which is a very precious piece of information. Here | |
662 | are the different kinds of assertions used in the tutorial, with a small | |
663 | description of their particularities. For more details, you should check | |
664 | the [reference on assertions](@ref group-assertions). | |
665 | ||
666 | assertion | description | |
667 | :--------------------------- | :---------- | |
668 | `BOOST_HANA_RUNTIME_CHECK` | Assertion on a condition that is not known until runtime. This assertion provides the weakest form of guarantee. | |
669 | `BOOST_HANA_CONSTEXPR_CHECK` | Assertion on a condition that would be `constexpr` if lambdas were allowed inside constant expressions. In other words, the only reason for it not being a `static_assert` is the language limitation that lambdas can't appear in constant expressions, which [might be lifted][N4487] in C++17. | |
670 | `static_assert` | Assertion on a `constexpr` condition. This is stronger than `BOOST_HANA_CONSTEXPR_CHECK` in that it requires the condition to be a constant expression, and it hence assures that the algorithms used in the expression are `constexpr`-friendly. | |
671 | `BOOST_HANA_CONSTANT_CHECK` | Assertion on a boolean `IntegralConstant`. This assertion provides the strongest form of guarantee, because an `IntegralConstant` can be converted to a `constexpr` value even if it is not `constexpr` itself. | |
672 | ||
673 | ||
674 | ||
675 | ||
676 | ||
677 | ||
678 | ||
679 | ||
680 | ||
681 | ||
682 | @section tutorial-integral Compile-time numbers | |
683 | ||
684 | ------------------------------------------------------------------------------ | |
685 | This section introduces the important notion of `IntegralConstant` and the | |
686 | philosophy behind Hana's metaprogramming paradigm. Let's start with a rather | |
687 | odd question. What is an `integral_constant`? | |
688 | ||
689 | @code{cpp} | |
690 | template<class T, T v> | |
691 | struct integral_constant { | |
692 | static constexpr T value = v; | |
693 | typedef T value_type; | |
694 | typedef integral_constant type; | |
695 | constexpr operator value_type() const noexcept { return value; } | |
696 | constexpr value_type operator()() const noexcept { return value; } | |
697 | }; | |
698 | @endcode | |
699 | ||
700 | @note | |
701 | If this is totally new to you, you might want to take a look at the | |
702 | [documentation][C++14.ice] for `std::integral_constant`. | |
703 | ||
704 | One valid answer is that `integral_constant` represents a type-level | |
705 | encoding of a number, or more generally any object of an integral type. | |
706 | For illustration, we could define a successor function on numbers in that | |
707 | representation very easily by using a template alias: | |
708 | ||
709 | @code{cpp} | |
710 | template <typename N> | |
711 | using succ = integral_constant<int, N::value + 1>; | |
712 | ||
713 | using one = integral_constant<int, 1>; | |
714 | using two = succ<one>; | |
715 | using three = succ<two>; | |
716 | // ... | |
717 | @endcode | |
718 | ||
719 | This is the way `integral_constant`s are usually thought of; as _type-level_ | |
720 | entities that can be used for template metaprogramming. Another way to see | |
721 | an `integral_constant` is as a runtime object representing a `constexpr` value | |
722 | of an integral type: | |
723 | ||
724 | @code{cpp} | |
725 | auto one = integral_constant<int, 1>{}; | |
726 | @endcode | |
727 | ||
728 | Here, while `one` is not marked as `constexpr`, the abstract value it holds | |
729 | (a `constexpr 1`) is still available at compile-time, because that value is | |
730 | encoded in the type of `one`. Indeed, even if `one` is not `constexpr`, we | |
731 | can use `decltype` to retrieve the compile-time value it represents: | |
732 | ||
733 | @code{cpp} | |
734 | auto one = integral_constant<int, 1>{}; | |
735 | constexpr int one_constexpr = decltype(one)::value; | |
736 | @endcode | |
737 | ||
738 | But why on earth would we want to consider `integral_constant`s as objects | |
739 | instead of type-level entities? To see why, consider how we could now | |
740 | implement the same successor function as before: | |
741 | ||
742 | @code{cpp} | |
743 | template <typename N> | |
744 | auto succ(N) { | |
745 | return integral_constant<int, N::value + 1>{}; | |
746 | } | |
747 | ||
748 | auto one = integral_constant<int, 1>{}; | |
749 | auto two = succ(one); | |
750 | auto three = succ(two); | |
751 | // ... | |
752 | @endcode | |
753 | ||
754 | Did you notice anything new? The difference is that instead of implementing | |
755 | `succ` at the type-level with a template alias, we're now implementing it at | |
756 | the value-level with a template function. Furthermore, we can now perform | |
757 | compile-time arithmetic using the same syntax as that of normal C++. This | |
758 | way of seeing compile-time entities as objects instead of types is the key | |
759 | to Hana's expressive power. | |
760 | ||
761 | ||
762 | @subsection tutorial-integral-arithmetic Compile-time arithmetic | |
763 | ||
764 | The MPL defines [arithmetic operators][MPL.arithmetic] that can be used to do | |
765 | compile-time computations with `integral_constant`s. A typical example of such | |
766 | an operation is `plus`, which is implemented roughly as: | |
767 | ||
768 | @code{cpp} | |
769 | template <typename X, typename Y> | |
770 | struct plus { | |
771 | using type = integral_constant< | |
772 | decltype(X::value + Y::value), | |
773 | X::value + Y::value | |
774 | >; | |
775 | }; | |
776 | ||
777 | using three = plus<integral_constant<int, 1>, | |
778 | integral_constant<int, 2>>::type; | |
779 | @endcode | |
780 | ||
781 | By viewing `integral_constant`s as objects instead of types, the translation | |
782 | from a metafunction to a function is very straightforward: | |
783 | ||
784 | @code{cpp} | |
785 | template <typename V, V v, typename U, U u> | |
786 | constexpr auto | |
787 | operator+(integral_constant<V, v>, integral_constant<U, u>) | |
788 | { return integral_constant<decltype(v + u), v + u>{}; } | |
789 | ||
790 | auto three = integral_constant<int, 1>{} + integral_constant<int, 2>{}; | |
791 | @endcode | |
792 | ||
793 | It is very important to emphasize the fact that this operator does not return | |
794 | a normal integer. Instead, it returns a value-initialized object whose type | |
795 | contains the result of the addition. The only useful information contained in | |
796 | that object is actually in its type, and we're creating an object because it | |
797 | allows us to use this nice value-level syntax. It turns out that we can make | |
798 | this syntax even better by using a [C++14 variable template][C++14.vtemplate] | |
799 | to simplify the creation of an `integral_constant`: | |
800 | ||
801 | @code{cpp} | |
802 | template <int i> | |
803 | constexpr integral_constant<int, i> int_c{}; | |
804 | ||
805 | auto three = int_c<1> + int_c<2>; | |
806 | @endcode | |
807 | ||
808 | Now we're talking about a visible gain in expressiveness over the initial | |
809 | type-level approach, aren't we? But there's more; we can also use | |
810 | [C++14 user defined literals][C++14.udl] to make this process even simpler: | |
811 | ||
812 | @code{cpp} | |
813 | template <char ...digits> | |
814 | constexpr auto operator"" _c() { | |
815 | // parse the digits and return an integral_constant | |
816 | } | |
817 | ||
818 | auto three = 1_c + 3_c; | |
819 | @endcode | |
820 | ||
821 | Hana provides its own `integral_constant`s, which define arithmetic operators | |
822 | just like we showed above. Hana also provides variable templates to easily | |
823 | create different kinds of `integral_constant`s: `int_c`, `long_c`, `bool_c`, | |
824 | etc... This allows you to omit the trailing `{}` braces otherwise required to | |
825 | value-initialize these objects. Of course, the `_c` suffix is also provided; | |
826 | it is part of the `hana::literals` namespace, and you must import it into | |
827 | your namespace before using it: | |
828 | ||
829 | @code{cpp} | |
830 | using namespace hana::literals; | |
831 | ||
832 | auto three = 1_c + 3_c; | |
833 | @endcode | |
834 | ||
835 | This way, you may do compile-time arithmetic without having to struggle with | |
836 | awkward type-level idiosyncrasies, and your coworkers will now be able to | |
837 | understand what's going on. | |
838 | ||
839 | ||
840 | @subsection tutorial-integral-distance Example: Euclidean distance | |
841 | ||
842 | To illustrate how good it gets, let's implement a function computing a 2-D | |
843 | euclidean distance at compile-time. As a reminder, the euclidean distance of | |
844 | two points in the 2-D plane is given by | |
845 | ||
846 | @f[ | |
847 | \mathrm{distance}\left((x_1, y_1), (x_2, y_2)\right) | |
848 | := \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2} | |
849 | @f] | |
850 | ||
851 | First, here's how it looks like with a type-level approach (using the MPL): | |
852 | ||
853 | @snippet example/tutorial/integral.cpp distance-mpl | |
854 | ||
855 | Yeah... Now, let's implement it with the value-level approach presented above: | |
856 | ||
857 | @snippet example/tutorial/integral.cpp distance-hana | |
858 | ||
859 | This version looks arguably cleaner. However, this is not all. Notice how the | |
860 | `distance` function looks exactly as the one you would have written for | |
861 | computing the euclidean distance on dynamic values? Indeed, because we're | |
862 | using the same syntax for dynamic and compile-time arithmetic, generic | |
863 | functions written for one will work for both! | |
864 | ||
865 | @snippet example/tutorial/integral.cpp distance-dynamic | |
866 | ||
867 | __Without changing any code__, we can use our `distance` function on runtime | |
868 | values and everything just works. Now that's DRY. | |
869 | ||
870 | ||
871 | @subsection tutorial-integral-branching Compile-time branching | |
872 | ||
873 | Once we have compile-time arithmetic, the next thing that might come to mind | |
874 | is compile-time branching. When metaprogramming, it is often useful to have | |
875 | one piece of code be compiled if some condition is true, and a different one | |
876 | otherwise. If you have heard of [static_if][N4461], this should sound very | |
877 | familiar, and indeed it is exactly what we are talking about. Otherwise, if | |
878 | you don't know why we might want to branch at compile-time, consider the | |
879 | following code (adapted from [N4461][]): | |
880 | ||
881 | @code{cpp} | |
882 | template <typename T, typename ...Args> | |
883 | std::enable_if_t<std::is_constructible<T, Args...>::value, | |
884 | std::unique_ptr<T>> make_unique(Args&&... args) { | |
885 | return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); | |
886 | } | |
887 | ||
888 | template <typename T, typename ...Args> | |
889 | std::enable_if_t<!std::is_constructible<T, Args...>::value, | |
890 | std::unique_ptr<T>> make_unique(Args&&... args) { | |
891 | return std::unique_ptr<T>(new T{std::forward<Args>(args)...}); | |
892 | } | |
893 | @endcode | |
894 | ||
895 | This code creates a `std::unique_ptr` using the correct form of syntax for the | |
896 | constructor. To achieve this, it uses [SFINAE][] and requires two different | |
897 | overloads. Now, anyone sane seeing this for the first time would ask why it | |
898 | is not possible to simply write: | |
899 | ||
900 | @code{cpp} | |
901 | template <typename T, typename ...Args> | |
902 | std::unique_ptr<T> make_unique(Args&&... args) { | |
903 | if (std::is_constructible<T, Args...>::value) | |
904 | return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); | |
905 | else | |
906 | return std::unique_ptr<T>(new T{std::forward<Args>(args)...}); | |
907 | } | |
908 | @endcode | |
909 | ||
910 | The reason is that the compiler is required to compile both branches of the | |
911 | `if` statement, regardless of the condition (even though it is known at | |
912 | compile-time). But when `T` is _not_ constructible from `Args...`, the second | |
913 | branch will fail to compile, which will cause a hard compilation error. What | |
914 | we need really is a way to tell the compiler __not to compile__ the second | |
915 | branch when the condition is true, and the first branch when the condition is | |
916 | false. | |
917 | ||
918 | To emulate this, Hana provides an `if_` function that works a bit like a | |
919 | normal `if` statement, except except it takes a condition that can be an | |
920 | `IntegralConstant` and returns the one of two values (which may have | |
921 | different types) chosen by the condition. If the condition is true, the | |
922 | first value is returned, and otherwise the second value is returned. A | |
923 | somewhat vain example is the following: | |
924 | ||
925 | @code{cpp} | |
926 | auto one_two_three = hana::if_(hana::true_c, 123, "hello"); | |
927 | auto hello = hana::if_(hana::false_c, 123, "hello"); | |
928 | @endcode | |
929 | ||
930 | @note | |
931 | `hana::true_c` and `hana::false_c` are just boolean `IntegralConstant`s | |
932 | representing a compile-time true value and a compile-time false value, | |
933 | respectively. | |
934 | ||
935 | Here, `one_two_three` is equal to `123`, and `hello` is equal to `"hello"`. | |
936 | In other words, `if_` is a little bit like the ternary conditional operator | |
937 | `? :`, except that both sides of the `:` can have different types: | |
938 | ||
939 | @code{cpp} | |
940 | // fails in both cases because both branches have incompatible types | |
941 | auto one_two_three = hana::true_c ? 123 : "hello"; | |
942 | auto hello = hana::false_c ? 123 : "hello"; | |
943 | @endcode | |
944 | ||
945 | Ok, so this is neat, but how can it actually help us write complete branches | |
946 | that are lazily instantiated by the compiler? The answer is to represent both | |
947 | branches of the `if` statement we'd like to write as generic lambdas, and to | |
948 | use `hana::if_` to return the branch that we'd like to execute. Here's how we | |
949 | could rewrite `make_unique`: | |
950 | ||
951 | @snippet example/tutorial/integral-branching.cpp make_unique.if_ | |
952 | ||
953 | Here, the first value given to `hana::if_` is a generic lambda representing | |
954 | the branch we want to execute if the condition is true, and the second value | |
955 | is the branch we want to execute otherwise. `hana::if_` simply returns the | |
956 | branch chosen by the condition, and we call that branch (which is a generic | |
957 | lambda) immediately with `std::forward<Args>(args)...`. Hence, the proper | |
958 | generic lambda ends up being called, with `x...` being `args...`, and we | |
959 | return the result of that call. | |
960 | ||
961 | The reason why this approach works is because the body of each branch can only | |
962 | be instantiated when the types of all `x...` are known. Indeed, since the | |
963 | branch is a generic lambda, the type of the argument is not known until the | |
964 | lambda is called, and the compiler must wait for the types of `x...` to be | |
965 | known before type-checking the lambda's body. Since the erroneous lambda is | |
966 | never called when the condition is not satisfied (`hana::if_` takes care of | |
967 | that), the body of the lambda that would fail is never type-checked and no | |
968 | compilation error happens. | |
969 | ||
970 | @note | |
971 | The branches inside the `if_` are lambdas. As such, they really are different | |
972 | functions from the `make_unique` function. The variables appearing inside | |
973 | those branches have to be either captured by the lambdas or passed to them as | |
974 | arguments, and so they are affected by the way they are captured or passed | |
975 | (by value, by reference, etc..). | |
976 | ||
977 | Since this pattern of expressing branches as lambdas and then calling them | |
978 | is very common, Hana provides a `eval_if` function whose purpose is to make | |
979 | compile-time branching easier. `eval_if` comes from the fact that in a lambda, | |
980 | one can either receive input data as arguments or capture it from the context. | |
981 | However, for the purpose of emulating a language level `if` statement, | |
982 | implicitly capturing variables from the enclosing scope is usually more | |
983 | natural. Hence, what we would prefer writing is | |
984 | ||
985 | @code{cpp} | |
986 | template <typename T, typename ...Args> | |
987 | std::unique_ptr<T> make_unique(Args&&... args) { | |
988 | return hana::if_(std::is_constructible<T, Args...>{}, | |
989 | [&] { return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); }, | |
990 | [&] { return std::unique_ptr<T>(new T{std::forward<Args>(args)...}); } | |
991 | ); | |
992 | } | |
993 | @endcode | |
994 | ||
995 | Here, we're capturing the `args...` variables from the enclosing scope, which | |
996 | prevents us from having to introduce the new `x...` variables and passing them | |
997 | as arguments to the branches. However, this has two problems. First, this will | |
998 | not achieve the right result, since `hana::if_` will end up returning a lambda | |
999 | instead of returning the result of calling that lambda. To fix this, we can use | |
1000 | `hana::eval_if` instead of `hana::if_`: | |
1001 | ||
1002 | @code{cpp} | |
1003 | template <typename T, typename ...Args> | |
1004 | std::unique_ptr<T> make_unique(Args&&... args) { | |
1005 | return hana::eval_if(std::is_constructible<T, Args...>{}, | |
1006 | [&] { return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); }, | |
1007 | [&] { return std::unique_ptr<T>(new T{std::forward<Args>(args)...}); } | |
1008 | ); | |
1009 | } | |
1010 | @endcode | |
1011 | ||
1012 | Here, we capture the enclosing `args...` by reference using `[&]`, and we do | |
1013 | not need to receive any arguments. Also, `hana::eval_if` assumes that its | |
1014 | arguments are branches that can be called, and it will take care of calling | |
1015 | the branch that is selected by the condition. However, this will still cause | |
1016 | a compilation failure, because the bodies of the lambdas are not dependent | |
1017 | anymore, and semantic analysis will be done for both branches even though | |
1018 | only one would end up being used. The solution to this problem is to make | |
1019 | the bodies of the lambdas artificially dependent on something, to prevent the | |
1020 | compiler from being able to perform semantic analysis before the lambda is | |
1021 | actually used. To make this possible, `hana::eval_if` will call the selected | |
1022 | branch with an identity function (a function that returns its argument | |
1023 | unchanged), if the branch accepts such an argument: | |
1024 | ||
1025 | @snippet example/tutorial/integral-branching.cpp make_unique.eval_if | |
1026 | ||
1027 | Here, the bodies of the branches take an additional argument called `_` by | |
1028 | convention. This argument will be provided by `hana::eval_if` to the branch | |
1029 | that was selected. Then, we use `_` as a function on the variables that we | |
1030 | want to make dependent within the body of each branch. What happens is that | |
1031 | `_` will always be a function that returns its argument unchanged. However, | |
1032 | the compiler can't possibly know it before the lambda has actually been called, | |
1033 | so it can't know the type of `_(args)`. This prevents the compiler from being | |
1034 | able to perform semantic analysis, and no compilation error happens. Plus, | |
1035 | since `_(x)` is guaranteed to be equivalent to `x`, we know that we're not | |
1036 | actually changing the semantics of the branches by using this trick. | |
1037 | ||
1038 | While using this trick may seem cumbersome, it can be very useful when dealing | |
1039 | with many variables inside a branch. Furthermore, it is not required to wrap | |
1040 | all variables with `_`; only variables that are involved in an expression whose | |
1041 | type-checking has to be delayed must be wrapped, but the other ones are not | |
1042 | required. There are still a few things to know about compile-time branching | |
1043 | in Hana, but you can dig deeper by looking at the reference for `hana::eval_if`, | |
1044 | `hana::if_` and `hana::lazy`. | |
1045 | ||
1046 | ||
1047 | @subsection tutorial-integral-more Why stop here? | |
1048 | ||
1049 | Why should we limit ourselves to arithmetic operations and branching? When you | |
1050 | start considering `IntegralConstant`s as objects, it becomes sensible to augment | |
1051 | their interface with more functions that are generally useful. For example, | |
1052 | Hana's `IntegralConstant`s define a `times` member function that can be used | |
1053 | to invoke a function a certain number of times, which is especially useful | |
1054 | for loop unrolling: | |
1055 | ||
1056 | @code{cpp} | |
1057 | __attribute__((noinline)) void f() { } | |
1058 | ||
1059 | int main() { | |
1060 | hana::int_c<10>.times(f); | |
1061 | } | |
1062 | @endcode | |
1063 | ||
1064 | In the above code, the 10 calls to `f` are expanded at compile-time. In other | |
1065 | words, this is equivalent to writing | |
1066 | ||
1067 | @code{cpp} | |
1068 | f(); f(); ... f(); // 10 times | |
1069 | @endcode | |
1070 | ||
1071 | @note | |
1072 | Always [be careful][Chandler.MeetingC++] about manually unrolling loops or | |
1073 | doing other such optimizations manually. In most cases, your compiler is | |
1074 | probably better than you at optimizing. When in doubt, benchmark. | |
1075 | ||
1076 | Another nice use of `IntegralConstant`s is to define good-looking operators | |
1077 | for indexing heterogeneous sequences. Whereas `std::tuple` must be accessed | |
1078 | with `std::get`, `hana::tuple` can be accessed using the familiar `operator[]` | |
1079 | used for standard library containers: | |
1080 | ||
1081 | @code{cpp} | |
1082 | auto values = hana::make_tuple(1, 'x', 3.4f); | |
1083 | char x = values[1_c]; | |
1084 | @endcode | |
1085 | ||
1086 | How this works is very simple. Basically, `hana::tuple` defines an `operator[]` | |
1087 | taking an `IntegralConstant` instead of a normal integer, in a way similar to | |
1088 | ||
1089 | @code{cpp} | |
1090 | template <typename N> | |
1091 | constexpr decltype(auto) operator[](N const&) { | |
1092 | return std::get<N::value>(*this); | |
1093 | } | |
1094 | @endcode | |
1095 | ||
1096 | This is the end of the section on `IntegralConstant`s. This section introduced | |
1097 | the feel behind Hana's new way of metaprogramming; if you liked what you've | |
1098 | seen so far, the rest of this tutorial should feel just like home. | |
1099 | ||
1100 | ||
1101 | ||
1102 | ||
1103 | ||
1104 | ||
1105 | ||
1106 | ||
1107 | ||
1108 | ||
1109 | @section tutorial-type Type computations | |
1110 | ||
1111 | ------------------------------------------------------------------------------ | |
1112 | At this point, if you are interested in doing type-level computations as with | |
1113 | the MPL, you might be wondering how is Hana going to help you. Do not despair. | |
1114 | Hana provides a way to perform type-level computations with a great deal of | |
1115 | expressiveness by representing types as values, just like we represented | |
1116 | compile-time numbers as values. This is a completely new way of approaching | |
1117 | metaprogramming, and you should try to set your old MPL habits aside for a bit | |
1118 | if you want to become proficient with Hana. | |
1119 | ||
1120 | However, please be aware that modern C++ features like [auto-deduced return type] | |
1121 | [C++14.auto_rt] remove the need for type computations in many cases. Hence, | |
1122 | before even considering to do a type computation, you should ask yourself | |
1123 | whether there's a simpler way to achieve what you're trying to achieve. In | |
1124 | most cases, the answer will be yes. However, when the answer is no, Hana will | |
1125 | provide you with nuclear-strength facilities to do what needs to be done. | |
1126 | ||
1127 | ||
1128 | @subsection tutorial-type-objects Types as objects | |
1129 | ||
1130 | The key behind Hana's approach to type-level computations is essentially the | |
1131 | same as the approach to compile-time arithmetic. Basically, the idea is to | |
1132 | represent compile-time entities as objects by wrapping them into some kind of | |
1133 | container. For `IntegralConstant`s, the compile-time entities were constant | |
1134 | expressions of an integral type and the wrapper we used was `integral_constant`. | |
1135 | In this section, the compile-time entities will be types and the wrapper we'll | |
1136 | be using is called `type`. Just like we did for `IntegralConstant`s, let's | |
1137 | start by defining a dummy template that could be used to represent a type: | |
1138 | ||
1139 | @code{cpp} | |
1140 | template <typename T> | |
1141 | struct basic_type { | |
1142 | // empty (for now) | |
1143 | }; | |
1144 | ||
1145 | basic_type<int> Int{}; | |
1146 | basic_type<char> Char{}; | |
1147 | // ... | |
1148 | @endcode | |
1149 | ||
1150 | @note | |
1151 | We're using the name `basic_type` here because we're only building a naive | |
1152 | version of the actual functionality provided by Hana. | |
1153 | ||
1154 | While this may seem completely useless, it is actually enough to start writing | |
1155 | metafunctions that look like functions. Indeed, consider the following | |
1156 | alternate implementations of `std::add_pointer` and `std::is_pointer`: | |
1157 | ||
1158 | @code{cpp} | |
1159 | template <typename T> | |
1160 | constexpr basic_type<T*> add_pointer(basic_type<T> const&) | |
1161 | { return {}; } | |
1162 | ||
1163 | template <typename T> | |
1164 | constexpr auto is_pointer(basic_type<T> const&) | |
1165 | { return hana::bool_c<false>; } | |
1166 | ||
1167 | template <typename T> | |
1168 | constexpr auto is_pointer(basic_type<T*> const&) | |
1169 | { return hana::bool_c<true>; } | |
1170 | @endcode | |
1171 | ||
1172 | We've just written metafunctions that look like functions, just like we wrote | |
1173 | compile-time arithmetic metafunctions as heterogeneous C++ operators in the | |
1174 | previous section. Here's how we can use them: | |
1175 | ||
1176 | @code{cpp} | |
1177 | basic_type<int> t{}; | |
1178 | auto p = add_pointer(t); | |
1179 | BOOST_HANA_CONSTANT_CHECK(is_pointer(p)); | |
1180 | @endcode | |
1181 | ||
1182 | Notice how we can now use a normal function call syntax to perform type-level | |
1183 | computations? This is analogous to how using values for compile-time numbers | |
1184 | allowed us to use normal C++ operators to perform compile-time computations. | |
1185 | Like we did for `integral_constant`, we can also go one step further and use | |
1186 | C++14 variable templates to provide syntactic sugar for creating types: | |
1187 | ||
1188 | @code{cpp} | |
1189 | template <typename T> | |
1190 | constexpr basic_type<T> type_c{}; | |
1191 | ||
1192 | auto t = type_c<int>; | |
1193 | auto p = add_pointer(t); | |
1194 | BOOST_HANA_CONSTANT_CHECK(is_pointer(p)); | |
1195 | @endcode | |
1196 | ||
1197 | @note | |
1198 | This is not exactly how the `hana::type_c` variable template is implemented | |
1199 | because of some subtleties; things were dumbed down here for the sake of the | |
1200 | explanation. Please check the reference for `hana::type` to know exactly | |
1201 | what you can expect from a `hana::type_c<...>`. | |
1202 | ||
1203 | ||
1204 | @subsection tutorial-type-benefits Benefits of this representation | |
1205 | ||
1206 | But what does that buy us? Well, since a `type_c<...>` is just an object, we | |
1207 | can store it in a heterogeneous sequence like a tuple, we can move it around | |
1208 | and pass it to (or return it from) functions, and we can do basically anything | |
1209 | else that requires an object: | |
1210 | ||
1211 | @snippet example/tutorial/type.cpp tuple | |
1212 | ||
1213 | @note | |
1214 | Writing `make_tuple(type_c<T>...)` can be annoying when there are several types. | |
1215 | For this reason, Hana provides the `tuple_t<T...>` variable template, which is | |
1216 | syntactic sugar for `make_tuple(type_c<T>...)`. | |
1217 | ||
1218 | Also, notice that since the above tuple is really just a normal heterogeneous | |
1219 | sequence, we can apply heterogeneous algorithms on that sequence just like we | |
1220 | could on a tuple of `int`s, for example. Furthermore, since we're just | |
1221 | manipulating objects, we can now use the full language instead of just the | |
1222 | small subset available at the type-level. For example, consider the task of | |
1223 | removing all the types that are not a reference or a pointer from a sequence | |
1224 | of types. With the MPL, we would have to use a placeholder expression to | |
1225 | express the predicate, which is clunky: | |
1226 | ||
1227 | @snippet example/tutorial/type.cpp filter.MPL | |
1228 | ||
1229 | Now, since we're manipulating objects, we can use the full language and use a | |
1230 | generic lambda instead, which leads to much more readable code: | |
1231 | ||
1232 | @snippet example/tutorial/type.cpp filter.Hana | |
1233 | ||
1234 | Since Hana handles all heterogeneous containers uniformly, this approach of | |
1235 | representing types as values also has the benefit that a single library is | |
1236 | now needed for both heterogeneous computations and type level computations. | |
1237 | Indeed, whereas we would normally need two different libraries to perform | |
1238 | almost identical tasks, we now need a single library. Again, consider the | |
1239 | task of filtering a sequence with a predicate. With MPL and Fusion, this | |
1240 | is what we must do: | |
1241 | ||
1242 | @snippet example/tutorial/type.cpp single_library.then | |
1243 | ||
1244 | With Hana, a single library is required. Notice how we use the same `filter` | |
1245 | algorithm and the same container, and only tweak the predicate so it can | |
1246 | operate on values: | |
1247 | ||
1248 | @snippet example/tutorial/type.cpp single_library.Hana | |
1249 | ||
1250 | But that is not all. Indeed, having a unified syntax for type-level and | |
1251 | value-level computations allows us to achieve greater consistency in the | |
1252 | interface of heterogeneous containers. For example, consider the simple | |
1253 | task of creating a heterogeneous map associating types to values, and then | |
1254 | accessing an element of it. With Fusion, what's happening is far from obvious | |
1255 | to the untrained eye: | |
1256 | ||
1257 | @snippet example/tutorial/type.cpp make_map.Fusion | |
1258 | ||
1259 | However, with a unified syntax for types and values, the same thing becomes | |
1260 | much clearer: | |
1261 | ||
1262 | @snippet example/tutorial/type.cpp make_map.Hana | |
1263 | ||
1264 | While Hana's way takes more lines of codes, it is also arguably more readable | |
1265 | and closer to how someone would expect to initialize a map. | |
1266 | ||
1267 | ||
1268 | @subsection tutorial-type-working Working with this representation | |
1269 | ||
1270 | So far, we can represent types as values and perform type-level computations | |
1271 | on those objects using the usual C++ syntax. This is nice, but it is not very | |
1272 | useful because we have no way to get back a normal C++ type from an object | |
1273 | representation. For example, how could we declare a variable whose type is the | |
1274 | result of a type computation? | |
1275 | ||
1276 | @code{cpp} | |
1277 | auto t = add_pointer(hana::type_c<int>); // could be a complex type computation | |
1278 | using T = the-type-represented-by-t; | |
1279 | ||
1280 | T var = ...; | |
1281 | @endcode | |
1282 | ||
1283 | Right now, there is no easy way to do it. To make this easier to achieve, we | |
1284 | enrich the interface of the `basic_type` container that we defined above. | |
1285 | Instead of being an empty `struct`, we now define it as | |
1286 | ||
1287 | @code{cpp} | |
1288 | template <typename T> | |
1289 | struct basic_type { | |
1290 | using type = T; | |
1291 | }; | |
1292 | @endcode | |
1293 | ||
1294 | @note | |
1295 | This is equivalent to making `basic_type` a metafunction in the MPL sense. | |
1296 | ||
1297 | This way, we can use `decltype` to easily access the actual C++ type | |
1298 | represented by a `type_c<...>` object: | |
1299 | ||
1300 | @code{cpp} | |
1301 | auto t = add_pointer(hana::type_c<int>); | |
1302 | using T = decltype(t)::type; // fetches basic_type<T>::type | |
1303 | ||
1304 | T var = ...; | |
1305 | @endcode | |
1306 | ||
1307 | In general, doing type-level metaprogramming with Hana is a three step process: | |
1308 | ||
1309 | 1. Represent types as objects by wrapping them with `hana::type_c<...>` | |
1310 | 2. Perform type transformations with value syntax | |
1311 | 3. Unwrap the result with `decltype(...)::%type` | |
1312 | ||
1313 | Now, you must be thinking that this is incredibly cumbersome. In reality, it | |
1314 | is very manageable for several reasons. First, this wrapping and unwrapping | |
1315 | only needs to happen at some very thin boundaries. | |
1316 | ||
1317 | @code{cpp} | |
1318 | auto t = hana::type_c<T>; | |
1319 | auto result = huge_type_computation(t); | |
1320 | using Result = decltype(result)::type; | |
1321 | @endcode | |
1322 | ||
1323 | Furthermore, since you get the advantage of working with objects (without | |
1324 | having to wrap/unwrap) inside the computation, the cost of wrapping and | |
1325 | unwrapping is amortized on the whole computation. Hence, for complex type | |
1326 | computations, the syntactic noise of this three step process quickly becomes | |
1327 | negligible in light of the expressiveness gain of working with values inside | |
1328 | that computation. Also, using values instead of types means that we can avoid | |
1329 | typing `typename` and `template` all around the place, which accounted for a | |
1330 | lot of syntactic noise in classic metaprogramming. | |
1331 | ||
1332 | Another point is that the three full steps are not always required. Indeed, | |
1333 | sometimes one just needs to do a type-level computation and query something | |
1334 | about the result, without necessarily fetching the result as a normal C++ type: | |
1335 | ||
1336 | @code{cpp} | |
1337 | auto t = hana::type_c<T>; | |
1338 | auto result = type_computation(t); | |
1339 | BOOST_HANA_CONSTANT_CHECK(is_pointer(result)); // third step skipped | |
1340 | @endcode | |
1341 | ||
1342 | In this case, we were able to skip the third step because we did not need to | |
1343 | access the actual type represented by `result`. In other cases, the first step | |
1344 | can be avoided, like when using `tuple_t`, which has no more syntactic noise | |
1345 | than any other pure type-level approach: | |
1346 | ||
1347 | @snippet example/tutorial/type.cpp skip_first_step | |
1348 | ||
1349 | For skeptical readers, let's consider the task of finding the smallest type | |
1350 | in a sequence of types. This is a very good example of a short type-only | |
1351 | computation, which is where we would expect the new paradigm to suffer the | |
1352 | most. As you will see, things stay manageable even for small computations. | |
1353 | First, let's implement it with the MPL: | |
1354 | ||
1355 | @snippet example/tutorial/type.cpp smallest.MPL | |
1356 | ||
1357 | The result is quite readable (for anyone familiar with the MPL). Let's now | |
1358 | implement the same thing using Hana: | |
1359 | ||
1360 | @snippet example/tutorial/type.cpp smallest.Hana | |
1361 | ||
1362 | As you can witness, the syntactic noise of the 3-step process is almost | |
1363 | completely hidden by the rest of the computation. | |
1364 | ||
1365 | ||
1366 | @subsection tutorial-type-lifting The generic lifting process | |
1367 | ||
1368 | The first type-level computation that we introduced in the form of a function | |
1369 | looked like: | |
1370 | ||
1371 | @code{cpp} | |
1372 | template <typename T> | |
1373 | constexpr auto add_pointer(hana::basic_type<T> const&) { | |
1374 | return hana::type<T*>; | |
1375 | } | |
1376 | @endcode | |
1377 | ||
1378 | While it looks more complicated, we could also write it as: | |
1379 | ||
1380 | @code{cpp} | |
1381 | template <typename T> | |
1382 | constexpr auto add_pointer(hana::basic_type<T> const&) { | |
1383 | return hana::type_c<typename std::add_pointer<T>::type>; | |
1384 | } | |
1385 | @endcode | |
1386 | ||
1387 | However, this implementation emphasizes the fact that we're really emulating | |
1388 | an existing metafunction and simply representing it as a function. In other | |
1389 | words, we're _lifting_ a metafunction (`std::add_pointer`) to the world of | |
1390 | values by creating our own `add_pointer` function. It turns out that this | |
1391 | lifting process is a generic one. Indeed, given any metafunction, we could | |
1392 | write almost the same thing: | |
1393 | ||
1394 | @code{cpp} | |
1395 | template <typename T> | |
1396 | constexpr auto add_const(hana::basic_type<T> const&) | |
1397 | { return hana::type_c<typename std::add_const<T>::type>; } | |
1398 | ||
1399 | template <typename T> | |
1400 | constexpr auto add_volatile(hana::basic_type<T> const&) | |
1401 | { return hana::type_c<typename std::add_volatile<T>::type>; } | |
1402 | ||
1403 | template <typename T> | |
1404 | constexpr auto add_lvalue_reference(hana::basic_type<T> const&) | |
1405 | { return hana::type_c<typename std::add_lvalue_reference<T>::type>; } | |
1406 | ||
1407 | // etc... | |
1408 | @endcode | |
1409 | ||
1410 | This mechanical transformation is easy to abstract into a generic lifter | |
1411 | that can handle any [MPL Metafunction][MPL.metafunction] as follows: | |
1412 | ||
1413 | @snippet example/tutorial/type.cpp metafunction1 | |
1414 | ||
1415 | More generally, we'll want to allow metafunctions with any number of | |
1416 | arguments, which brings us to the following less naive implementation: | |
1417 | ||
1418 | @snippet example/tutorial/type.cpp metafunction2 | |
1419 | ||
1420 | Hana provides a similar generic metafunction lifter called `hana::metafunction`. | |
1421 | One small improvement is that `hana::metafunction<F>` is a function object | |
1422 | instead of an overloaded function, so one can pass it to higher-order | |
1423 | algorithms. It is also a model of the slightly more powerful concept of | |
1424 | `Metafunction`, but this can safely be ignored for now. The process we | |
1425 | explored in this section does not only apply to metafunctions; it also | |
1426 | applies to templates. Indeed, we could define: | |
1427 | ||
1428 | @snippet example/tutorial/type.cpp template_ | |
1429 | ||
1430 | Hana provides a generic lifter for templates named `hana::template_`, and it | |
1431 | also provides a generic lifter for [MPL MetafunctionClasses][MPL.mfc] named | |
1432 | `hana::metafunction_class`. This gives us a way to uniformly represent "legacy" | |
1433 | type-level computations as functions, so that any code written using a classic | |
1434 | type-level metaprogramming library can almost trivially be used with Hana. For | |
1435 | example, say you have a large chunk of MPL-based code and you'd like to | |
1436 | interface with Hana. The process of doing so is no harder than wrapping your | |
1437 | metafunctions with the lifter provided by Hana: | |
1438 | ||
1439 | @code{cpp} | |
1440 | template <typename T> | |
1441 | struct legacy { | |
1442 | using type = ...; // something you really don't want to mess with | |
1443 | }; | |
1444 | ||
1445 | auto types = hana::make_tuple(...); | |
1446 | auto use = hana::transform(types, hana::metafunction<legacy>); | |
1447 | @endcode | |
1448 | ||
1449 | However, note that not all type-level computations can be lifted as-is with | |
1450 | the tools provided by Hana. For example, `std::extent` can't be lifted because | |
1451 | it requires non-type template parameters. Since there is no way to deal with | |
1452 | non-type template parameters uniformly in C++, one must resort to using a | |
1453 | hand-written function object specific to that type-level computation: | |
1454 | ||
1455 | @snippet example/tutorial/type.cpp extent | |
1456 | ||
1457 | @note | |
1458 | Do not forget to include the bridge header for `std::integral_constant`s | |
1459 | (`<boost/hana/ext/std/integral_constant.hpp>`) when using type traits from | |
1460 | `<type_traits>` directly. | |
1461 | ||
1462 | In practice, however, this should not be a problem since the vast majority | |
1463 | of type-level computations can be lifted easily. Finally, since metafunctions | |
1464 | provided by the `<type_traits>` header are used so frequently, Hana provides | |
1465 | a lifted version for every one of them. Those lifted traits are in the | |
1466 | `hana::traits` namespace, and they live in the `<boost/hana/traits.hpp>` header: | |
1467 | ||
1468 | @snippet example/tutorial/type.cpp traits | |
1469 | ||
1470 | This is the end of the section on type computations. While this new paradigm | |
1471 | for type level programming might be difficult to grok at first, it will make | |
1472 | more sense as you use it more and more. You will also come to appreciate how | |
1473 | it blurs the line between types and values, opening new exciting possibilities | |
1474 | and simplifying many tasks. | |
1475 | ||
1476 | @note | |
1477 | Curious or skeptical readers should consider checking the minimal | |
1478 | reimplementation of the MPL presented in the [appendices] | |
1479 | (@ref tutorial-appendix-MPL). | |
1480 | ||
1481 | ||
1482 | ||
1483 | ||
1484 | ||
1485 | ||
1486 | ||
1487 | ||
1488 | ||
1489 | ||
1490 | @section tutorial-introspection Introspection | |
1491 | ||
1492 | ------------------------------------------------------------------------------ | |
1493 | Static introspection, as we will discuss it here, is the ability of a program | |
1494 | to examine the type of an object at compile-time. In other words, it is a | |
1495 | programmatic interface to interact with types at compile-time. For example, | |
1496 | have you ever wanted to check whether some unknown type has a member named | |
1497 | `foo`? Or perhaps at some point you have needed to iterate on the members | |
1498 | of a `struct`? | |
1499 | ||
1500 | @code{cpp} | |
1501 | struct Person { | |
1502 | std::string name; | |
1503 | int age; | |
1504 | }; | |
1505 | ||
1506 | Person john{"John", 30}; | |
1507 | for (auto& member : john) | |
1508 | std::cout << member.name << ": " << member.value << std::endl; | |
1509 | ||
1510 | // name: John | |
1511 | // age: 30 | |
1512 | @endcode | |
1513 | ||
1514 | If you have written a bit of templates in your life, chances are very high | |
1515 | that you came across the first problem of checking for a member. Also, anyone | |
1516 | having tried to implement object serialization or even just pretty printing | |
1517 | has come across the second problem. In most dynamic languages like Python, | |
1518 | Ruby or JavaScript, these problems are completely solved and introspection is | |
1519 | used every day by programmers to make a lot of tasks simpler. However, as a | |
1520 | C++ programmer, we do not have language support for those things, which makes | |
1521 | several tasks much harder than they should be. While language support would | |
1522 | likely be needed to properly tackle this problem, Hana makes some common | |
1523 | introspection patterns much more accessible. | |
1524 | ||
1525 | ||
1526 | @subsection tutorial-introspection-is_valid Checking expression validity | |
1527 | ||
1528 | Given an object of an unknown type, it is sometimes desirable to check | |
1529 | whether this object has a member (or member function) with some name. | |
1530 | This can be used to perform sophisticated flavors of overloading. For | |
1531 | example, consider the problem of calling a `toString` method on objects | |
1532 | that support it, but providing another default implementation for objects | |
1533 | that do not support it: | |
1534 | ||
1535 | @code{cpp} | |
1536 | template <typename T> | |
1537 | std::string optionalToString(T const& obj) { | |
1538 | if (obj.toString() is a valid expression) | |
1539 | return obj.toString(); | |
1540 | else | |
1541 | return "toString not defined"; | |
1542 | } | |
1543 | @endcode | |
1544 | ||
1545 | @note | |
1546 | While most use cases for this technique will be addressed by [concepts lite] | |
1547 | [C++17.clite] in future revisions of the standard, there will still be cases | |
1548 | where a quick and dirty check is more convenient than creating a full blown | |
1549 | concept. | |
1550 | ||
1551 | How could we implement a check for the validity of `obj.toString()` as above | |
1552 | in a generic fashion (so it can be reused in other functions, for example)? | |
1553 | Normally, we would be stuck writing some kind of SFINAE-based detection: | |
1554 | ||
1555 | @snippet example/tutorial/introspection.cpp has_toString.then | |
1556 | ||
1557 | This works, but the intent is not very clear and most people without a deep | |
1558 | knowledge of template metaprogramming would think this is black magic. Then, | |
1559 | we could implement `optionalToString` as | |
1560 | ||
1561 | @code{cpp} | |
1562 | template <typename T> | |
1563 | std::string optionalToString(T const& obj) { | |
1564 | if (has_toString<T>::value) | |
1565 | return obj.toString(); | |
1566 | else | |
1567 | return "toString not defined"; | |
1568 | } | |
1569 | @endcode | |
1570 | ||
1571 | @note | |
1572 | Of course, this implementation won't actually work because both branches of | |
1573 | the `if` statement will be compiled. If `obj` does not have a `toString` | |
1574 | method, the compilation of the `if` branch will fail. We will address | |
1575 | this issue in a moment. | |
1576 | ||
1577 | Instead of the above SFINAE trick, Hana provides a `is_valid` function that | |
1578 | can be combined with [C++14 generic lambdas][C++14.glambda] to obtain a much | |
1579 | cleaner implementation of the same thing: | |
1580 | ||
1581 | @snippet example/tutorial/introspection.cpp has_toString.now | |
1582 | ||
1583 | This leaves us with a function object `has_toString` which returns whether the | |
1584 | given expression is valid on the argument we pass to it. The result is returned | |
1585 | as an `IntegralConstant`, so `constexpr`-ness is not an issue here because the | |
1586 | result of the function is represented as a type anyway. Now, in addition to | |
1587 | being less verbose (that's a one liner!), the intent is much clearer. Other | |
1588 | benefits are the fact that `has_toString` can be passed to higher order | |
1589 | algorithms and it can also be defined at function scope, so there is no need | |
1590 | to pollute the namespace scope with implementation details. Here is how we | |
1591 | would now write `optionalToString`: | |
1592 | ||
1593 | @code{cpp} | |
1594 | template <typename T> | |
1595 | std::string optionalToString(T const& obj) { | |
1596 | if (has_toString(obj)) | |
1597 | return obj.toString(); | |
1598 | else | |
1599 | return "toString not defined"; | |
1600 | } | |
1601 | @endcode | |
1602 | ||
1603 | Much cleaner, right? However, as we said earlier, this implementation won't | |
1604 | actually work because both branches of the `if` always have to be compiled, | |
1605 | regardless of whether `obj` has a `toString` method. There are several | |
1606 | possible options, but the most classical one is to use `std::enable_if`: | |
1607 | ||
1608 | @snippet example/tutorial/introspection.cpp optionalToString.then | |
1609 | ||
1610 | @note | |
1611 | We're using the fact that `has_toString` returns an `IntegralConstant` to | |
1612 | write `decltype(...)::%value`, which is a constant expression. For some | |
1613 | reason, `has_toString(obj)` is not considered a constant expression, even | |
1614 | though I think it should be one because we never read from `obj` (see the | |
1615 | section on [advanced constexpr](@ref tutorial-appendix-constexpr)). | |
1616 | ||
1617 | While this implementation is perfectly valid, it is still pretty cumbersome | |
1618 | because it requires writing two different functions and going through the | |
1619 | hoops of SFINAE explicitly by using `std::enable_if`. However, as you might | |
1620 | remember from the section on [compile-time branching](@ref tutorial-integral-branching), | |
1621 | Hana provides an `if_` function that can be used to emulate the functionality | |
1622 | of [static_if][N4461]. Here is how we could write `optionalToString` with | |
1623 | `hana::if_`: | |
1624 | ||
1625 | @snippet example/tutorial/introspection.cpp optionalToString | |
1626 | ||
1627 | Now, the previous example covered only the specific case of checking for the | |
1628 | presence of a non-static member function. However, `is_valid` can be used to | |
1629 | detect the validity of almost any kind of expression. For completeness, we | |
1630 | now present a list of common use cases for validity checking along with how | |
1631 | to use `is_valid` to implement them. | |
1632 | ||
1633 | ||
1634 | @subsubsection tutorial-introspection-is_valid-non_static Non-static members | |
1635 | ||
1636 | The first idiom we'll look at is checking for the presence of a non-static | |
1637 | member. We can do it in a similar way as we did for the previous example: | |
1638 | ||
1639 | @snippet example/tutorial/introspection.cpp non_static_member_from_object | |
1640 | ||
1641 | Notice how we cast the result of `x.member` to `void`? This is to make sure | |
1642 | that our detection also works for types that can't be returned from functions, | |
1643 | like array types. Also, it is important to use a reference as the parameter to | |
1644 | our generic lambda, because that would otherwise require `x` to be | |
1645 | [CopyConstructible][], which is not what we're trying to check. This approach | |
1646 | is simple and the most convenient when an object is available. However, when | |
1647 | the checker is intended to be used with no object around, the following | |
1648 | alternate implementation can be better suited: | |
1649 | ||
1650 | @snippet example/tutorial/introspection.cpp non_static_member_from_type | |
1651 | ||
1652 | This validity checker is different from what we saw earlier because the | |
1653 | generic lambda is not expecting an usual object anymore; it is now expecting | |
1654 | a `type` (which is an object, but still represents a type). We then use the | |
1655 | `hana::traits::declval` _lifted metafunction_ from the `<boost/hana/traits.hpp>` | |
1656 | header to create an rvalue of the type represented by `t`, which we can then | |
1657 | use to check for a non-static member. Finally, instead of passing an actual | |
1658 | object to `has_member` (like `Foo{}` or `Bar{}`), we now pass a `type_c<...>`. | |
1659 | This implementation is ideal for when no object is lying around. | |
1660 | ||
1661 | ||
1662 | @subsubsection tutorial-introspection-is_valid-static Static members | |
1663 | ||
1664 | Checking for a static member is easy, and it is provided for completeness: | |
1665 | ||
1666 | @snippet example/tutorial/introspection.cpp static_member | |
1667 | ||
1668 | Again, we expect a `type` to be passed to the checker. Inside the generic | |
1669 | lambda, we use `decltype(t)::%type` to fetch the actual C++ type represented | |
1670 | by the `t` object, as explained in the section on [type computations] | |
1671 | (@ref tutorial-type-working). Then, we fetch the static member inside | |
1672 | that type and cast it to `void`, for the same reason as we did for non-static | |
1673 | members. | |
1674 | ||
1675 | ||
1676 | @subsubsection tutorial-introspection-is_valid-typename Nested type names | |
1677 | ||
1678 | Checking for a nested type name is not hard, but it is slightly more | |
1679 | convoluted than the previous cases: | |
1680 | ||
1681 | @snippet example/tutorial/introspection.cpp nested_type_name | |
1682 | ||
1683 | One might wonder why we use `-> hana::type<typename-expression>` instead | |
1684 | of simply `-> typename-expression`. Again, the reason is that we want to | |
1685 | support types that can't be returned from functions, like array types or | |
1686 | incomplete types. | |
1687 | ||
1688 | ||
1689 | @subsubsection tutorial-introspection-is_valid-template Nested templates | |
1690 | ||
1691 | Checking for a nested template name is similar to checking for a nested type | |
1692 | name, except we use the `template_<...>` variable template instead of | |
1693 | `type<...>` in the generic lambda: | |
1694 | ||
1695 | @snippet example/tutorial/introspection.cpp nested_template | |
1696 | ||
1697 | ||
1698 | @subsection tutorial-introspection-sfinae Taking control of SFINAE | |
1699 | ||
1700 | Doing something only if an expression is well-formed is a very common pattern | |
1701 | in C++. Indeed, the `optionalToString` function is just one instance of the | |
1702 | following pattern, which is very general: | |
1703 | ||
1704 | @code{cpp} | |
1705 | template <typename T> | |
1706 | auto f(T x) { | |
1707 | if (some expression involving x is well-formed) | |
1708 | return something involving x; | |
1709 | else | |
1710 | return something else; | |
1711 | } | |
1712 | @endcode | |
1713 | ||
1714 | To encapsulate this pattern, Hana provides the `sfinae` function, which allows | |
1715 | executing an expression, but only if it is well-formed: | |
1716 | ||
1717 | @snippet example/tutorial/introspection.sfinae.cpp maybe_add | |
1718 | ||
1719 | Here, we create a `maybe_add` function, which is simply a generic lambda | |
1720 | wrapped with Hana's `sfinae` function. `maybe_add` is a function which takes | |
1721 | two inputs and returns `just` the result of the generic lambda if that call | |
1722 | is well-formed, and `nothing` otherwise. `just(...)` and `nothing` both belong | |
1723 | to a type of container called `hana::optional`, which is essentially a | |
1724 | compile-time `std::optional`. All in all, `maybe_add` is morally equivalent | |
1725 | to the following function returning a `std::optional`, except that the check | |
1726 | is done at compile-time: | |
1727 | ||
1728 | @code{cpp} | |
1729 | auto maybe_add = [](auto x, auto y) { | |
1730 | if (x + y is well formed) | |
1731 | return std::optional<decltype(x + y)>{x + y}; | |
1732 | else | |
1733 | return std::optional<???>{}; | |
1734 | }; | |
1735 | @endcode | |
1736 | ||
1737 | It turns out that we can take advantage of `sfinae` and `optional` to | |
1738 | implement the `optionalToString` function as follows: | |
1739 | ||
1740 | @snippet example/tutorial/introspection.sfinae.cpp optionalToString.sfinae | |
1741 | ||
1742 | First, we wrap `toString` with the `sfinae` function. Hence, `maybe_toString` | |
1743 | is a function which either returns `just(x.toString())` if that is well-formed, | |
1744 | or `nothing` otherwise. Secondly, we use the `.value_or()` function to extract | |
1745 | the optional value from the container. If the optional value is `nothing`, | |
1746 | `.value_or()` returns the default value given to it; otherwise, it returns the | |
1747 | value inside the `just` (here `x.toString()`). This way of seeing SFINAE as a | |
1748 | special case of computations that might fail is very clean and powerful, | |
1749 | especially since `sfinae`'d functions can be combined through the | |
1750 | `hana::optional` `Monad`, which is left to the reference documentation. | |
1751 | ||
1752 | ||
1753 | @subsection tutorial-introspection-adapting Introspecting user-defined types | |
1754 | ||
1755 | Have you ever wanted to iterate over the members of a user-defined type? The | |
1756 | goal of this section is to show you how Hana can be used to do it quite easily. | |
1757 | To allow working with user-defined types, Hana defines the `Struct` concept. | |
1758 | Once a user-defined type is a model of that concept, one can iterate over the | |
1759 | members of an object of that type and query other useful information. To turn | |
1760 | a user-defined type into a `Struct`, a couple of options are available. First, | |
1761 | you may define the members of your user-defined type with the | |
1762 | `BOOST_HANA_DEFINE_STRUCT` macro: | |
1763 | ||
1764 | @snippet example/tutorial/introspection.adapt.cpp BOOST_HANA_DEFINE_STRUCT | |
1765 | ||
1766 | This macro defines two members (`name` and `age`) with the given types. Then, | |
1767 | it defines some boilerplate inside a `Person::hana` nested `struct`, which is | |
1768 | required to make `Person` a model of the `Struct` concept. No constructors are | |
1769 | defined (so [POD-ness][POD] is retained), the members are defined in the same | |
1770 | order as they appear here and the macro can be used with template `struct`s | |
1771 | just as well, and at any scope. Also note that you are free to add more | |
1772 | members to the `Person` type after or before you use the macro. However, | |
1773 | only members defined with the macro will be picked up when introspecting the | |
1774 | `Person` type. Easy enough? Now, a `Person` can be accessed programmatically: | |
1775 | ||
1776 | @snippet example/tutorial/introspection.adapt.cpp for_each | |
1777 | ||
1778 | Iteration over a `Struct` is done as if the `Struct` was a sequence of pairs, | |
1779 | where the first element of a pair is the key associated to a member, and the | |
1780 | second element is the member itself. When a `Struct` is defined through the | |
1781 | `BOOST_HANA_DEFINE_STRUCT` macro, the key associated to any member is a | |
1782 | compile-time `hana::string` representing the name of that member. This is why | |
1783 | the function used with `for_each` takes a single argument `pair`, and then | |
1784 | uses `first` and `second` to access the subparts of the pair. Also, notice | |
1785 | how the `to<char const*>` function is used on the name of the member? This | |
1786 | converts the compile-time string to a `constexpr char const*` so it can | |
1787 | `cout`ed. Since it can be annoying to always use `first` and `second` to | |
1788 | fetch the subparts of the pair, we can also use the `fuse` function to wrap | |
1789 | our lambda and make it a binary lambda instead: | |
1790 | ||
1791 | @snippet example/tutorial/introspection.adapt.cpp for_each.fuse | |
1792 | ||
1793 | Now, it looks much cleaner. As we just mentioned, `Struct`s are seen as a kind | |
1794 | of sequence of pairs for the purpose of iteration. In fact, a `Struct` can | |
1795 | even be searched like an associative data structure whose keys are the names | |
1796 | of the members, and whose values are the members themselves: | |
1797 | ||
1798 | @snippet example/tutorial/introspection.adapt.cpp at_key | |
1799 | ||
1800 | @note | |
1801 | The `_s` user-defined literal creates a compile-time `hana::string`. It is | |
1802 | located in the `boost::hana::literals` namespace. Note that it is not part | |
1803 | of the standard yet, but it is supported by Clang and GCC. If you want to | |
1804 | stay 100% standard, you can use the `BOOST_HANA_STRING` macro instead. | |
1805 | ||
1806 | The main difference between a `Struct` and a `hana::map` is that a map can be | |
1807 | modified (keys can be added and removed), while a `Struct` is immutable. | |
1808 | However, you can easily convert a `Struct` into a `hana::map` with `to<map_tag>`, | |
1809 | and then you can manipulate it in a more flexible way. | |
1810 | ||
1811 | @snippet example/tutorial/introspection.adapt.cpp to<map_tag> | |
1812 | ||
1813 | Using the `BOOST_HANA_DEFINE_STRUCT` macro to adapt a `struct` is convenient, | |
1814 | but sometimes one can't modify the type that needs to be adapted. In these | |
1815 | cases, the `BOOST_HANA_ADAPT_STRUCT` macro can be used to adapt a `struct` in | |
1816 | a ad-hoc manner: | |
1817 | ||
1818 | @snippet example/tutorial/introspection.adapt.cpp BOOST_HANA_ADAPT_STRUCT | |
1819 | ||
1820 | @note | |
1821 | The `BOOST_HANA_ADAPT_STRUCT` macro must be used at global scope. | |
1822 | ||
1823 | The effect is exactly the same as with the `BOOST_HANA_DEFINE_STRUCT` macro, | |
1824 | except you do not need to modify the type you want to adapt, which is | |
1825 | sometimes useful. Finally, it is also possible to define custom accessors | |
1826 | by using the `BOOST_HANA_ADAPT_ADT` macro: | |
1827 | ||
1828 | @snippet example/tutorial/introspection.adapt.cpp BOOST_HANA_ADAPT_ADT | |
1829 | ||
1830 | This way, the names used to access the members of the `Struct` will be those | |
1831 | specified, and the associated function will be called on the `Struct` when | |
1832 | retrieving that member. Before we move on to a concrete example of using these | |
1833 | introspection features, it should also be mentioned that `struct`s can be | |
1834 | adapted without using macros. This advanced interface for defining `Struct`s | |
1835 | can be used for example to specify keys that are not compile-time strings. | |
1836 | The advanced interface is described in the documentation of the `Struct` | |
1837 | concept. | |
1838 | ||
1839 | ||
1840 | @subsection tutorial-introspection-json Example: generating JSON | |
1841 | ||
1842 | Let's now move on with a concrete example of using the introspection | |
1843 | capabilities we just presented for printing custom objects as JSON. | |
1844 | Our end goal is to have something like this: | |
1845 | ||
1846 | @snippet example/tutorial/introspection.json.cpp usage | |
1847 | ||
1848 | And the output, after passing it through a JSON pretty-printer, | |
1849 | should look like | |
1850 | ||
1851 | @code{.json} | |
1852 | [ | |
1853 | { | |
1854 | "name": "John", | |
1855 | "last_name": "Doe", | |
1856 | "age": 30 | |
1857 | }, | |
1858 | { | |
1859 | "brand": "Audi", | |
1860 | "model": "A4" | |
1861 | }, | |
1862 | { | |
1863 | "brand": "BMW", | |
1864 | "model": "Z3" | |
1865 | } | |
1866 | ] | |
1867 | @endcode | |
1868 | ||
1869 | First, let's define a couple of utility functions to make string manipulation | |
1870 | easier: | |
1871 | ||
1872 | @snippet example/tutorial/introspection.json.cpp utilities | |
1873 | ||
1874 | The `quote` and the `to_json` overloads are pretty self-explanatory. The | |
1875 | `join` function, however, might need a bit of explanation. Basically, the | |
1876 | `intersperse` function takes a sequence and a separator, and returns a new | |
1877 | sequence with the separator in between each pair of elements of the original | |
1878 | sequence. In other words, we take a sequence of the form `[x1, ..., xn]` and | |
1879 | turn it into a sequence of the form `[x1, sep, x2, sep, ..., sep, xn]`. | |
1880 | Finally, we fold the resulting sequence with the `_ + _` function object, | |
1881 | which is equivalent to `std::plus<>{}`. Since our sequence contains | |
1882 | `std::string`s (we assume it does), this has the effect of concatenating | |
1883 | all the strings of the sequence into one big string. Now, let's define | |
1884 | how to print a `Sequence`: | |
1885 | ||
1886 | @snippet example/tutorial/introspection.json.cpp Sequence | |
1887 | ||
1888 | First, we use the `transform` algorithm to turn our sequence of objects into | |
1889 | a sequence of `std::string`s in JSON format. Then, we join that sequence with | |
1890 | commas and we enclose it with `[]` to denote a sequence in JSON notation. | |
1891 | Simple enough? Let's now take a look at how to print user-defined types: | |
1892 | ||
1893 | @snippet example/tutorial/introspection.json.cpp Struct | |
1894 | ||
1895 | Here, we use the `keys` method to retrieve a `tuple` containing the names of | |
1896 | the members of the user-defined type. Then, we `transform` that sequence into | |
1897 | a sequence of `"name" : member` strings, which we then `join` and enclose with | |
1898 | `{}`, which is used to denote objects in JSON notation. And that's it! | |
1899 | ||
1900 | ||
1901 | ||
1902 | ||
1903 | ||
1904 | ||
1905 | ||
1906 | ||
1907 | ||
1908 | ||
1909 | @section tutorial-containers Generalities on containers | |
1910 | ||
1911 | ------------------------------------------------------------------------------ | |
1912 | This section explains several important notions about Hana's containers: how | |
1913 | to create them, the lifetime of their elements and other concerns. | |
1914 | ||
1915 | ||
1916 | @subsection tutorial-containers-creating Container creation | |
1917 | ||
1918 | While the usual way of creating an object in C++ is to use its constructor, | |
1919 | heterogeneous programming makes things a bit more complicated. Indeed, in | |
1920 | most cases, one is not interested in (or even aware of) the actual type of | |
1921 | the heterogeneous container to be created. At other times, one could write | |
1922 | out that type explicitly, but it would be redundant or cumbersome to do so. | |
1923 | For this reason, Hana uses a different approach borrowed from `std::make_tuple` | |
1924 | to create new containers. Much like one can create a `std::tuple` with | |
1925 | `std::make_tuple`, a `hana::tuple` can be created with `hana::make_tuple`. | |
1926 | However, more generally, containers in Hana may be created with the `make` | |
1927 | function: | |
1928 | ||
1929 | @snippet example/tutorial/containers.cpp make<tuple_tag> | |
1930 | ||
1931 | In fact, `make_tuple` is just a shortcut for `make<tuple_tag>` so you don't | |
1932 | have to type `boost::hana::make<boost::hana::tuple_tag>` when you are out of | |
1933 | Hana's namespace. Simply put, `make<...>` is is used all around the library | |
1934 | to create different types of objects, thus generalizing the `std::make_xxx` | |
1935 | family of functions. For example, one can create a `hana::range` of | |
1936 | compile-time integers with `make<range_tag>`: | |
1937 | ||
1938 | @snippet example/tutorial/containers.cpp make<range_tag> | |
1939 | ||
1940 | > These types with a trailing `_tag` are dummy types __representing__ a family | |
1941 | > of heterogeneous containers (`hana::tuple`, `hana::map`, etc..). Tags are | |
1942 | > documented in the section on [Hana's core](@ref tutorial-core-tags). | |
1943 | ||
1944 | For convenience, whenever a component of Hana provides a `make<xxx_tag>` | |
1945 | function, it also provides the `make_xxx` shortcut to reduce typing. Also, an | |
1946 | interesting point that can be raised in this example is the fact that `r` is | |
1947 | `constexpr`. In general, whenever a container is initialized with constant | |
1948 | expressions only (which is the case for `r`), that container may be marked | |
1949 | as `constexpr`. | |
1950 | ||
1951 | So far, we have only created containers with the `make_xxx` family of | |
1952 | functions. However, some containers do provide constructors as part of | |
1953 | their interface. For example, one can create a `hana::tuple` just like | |
1954 | one would create a `std::tuple`: | |
1955 | ||
1956 | @snippet example/tutorial/containers.cpp tuple_constructor | |
1957 | ||
1958 | When constructors (or any member function really) are part of the public | |
1959 | interface, they will be documented on a per-container basis. However, | |
1960 | in the general case, one should not take for granted that a container | |
1961 | can be constructed as the tuple was constructed above. For example, | |
1962 | trying to create a `hana::range` that way will __not__ work: | |
1963 | ||
1964 | @code{.cpp} | |
1965 | hana::range<???> xs{hana::int_c<3>, hana::int_c<10>}; | |
1966 | @endcode | |
1967 | ||
1968 | In fact, we can't even specify the type of the object we'd like to create in | |
1969 | that case, because the exact type of a `hana::range` is implementation-defined, | |
1970 | which brings us to the next section. | |
1971 | ||
1972 | ||
1973 | @subsection tutorial-containers-types Container types | |
1974 | ||
1975 | The goal of this section is to clarify what can be expected from the types of | |
1976 | Hana's containers. Indeed, so far, we always let the compiler deduce the | |
1977 | actual type of containers by using the `make_xxx` family of functions along | |
1978 | with `auto`. But in general, what can we say about the type of a container? | |
1979 | ||
1980 | @snippet example/tutorial/containers.cpp types | |
1981 | ||
1982 | The answer is that it depends. Some containers have well defined types, while | |
1983 | others do not specify their representation. In this example, the type of the | |
1984 | object returned by `make_tuple` is well-defined, while the type returned by | |
1985 | `make_range` is implementation-defined: | |
1986 | ||
1987 | @snippet example/tutorial/containers.cpp types_maximally_specified | |
1988 | ||
1989 | This is documented on a per-container basis; when a container has an | |
1990 | implementation-defined representation, a note explaining exactly what | |
1991 | can be expected from that representation is included in the container's | |
1992 | description. There are several reasons for leaving the representation of | |
1993 | a container unspecified; they are explained in the | |
1994 | [rationales](@ref tutorial-rationales-container_representation). | |
1995 | When the representation of a container is implementation-defined, one must | |
1996 | be careful not to make any assumptions about it, unless those assumption | |
1997 | are explicitly allowed in the documentation of the container. | |
1998 | ||
1999 | ||
2000 | @subsubsection tutorial-containers-types-overloading Overloading on container types | |
2001 | ||
2002 | While necessary, leaving the type of some containers unspecified makes some | |
2003 | things very difficult to achieve, like overloading functions on heterogeneous | |
2004 | containers: | |
2005 | ||
2006 | @code{cpp} | |
2007 | template <typename T> | |
2008 | void f(std::vector<T> xs) { | |
2009 | // ... | |
2010 | } | |
2011 | ||
2012 | template <typename ...???> | |
2013 | void f(unspecified-range-type<???> r) { | |
2014 | // ... | |
2015 | } | |
2016 | @endcode | |
2017 | ||
2018 | The `is_a` utility is provided for this reason (and others). `is_a` allows | |
2019 | checking whether a type is a precise kind of container using its tag, | |
2020 | regardless of the actual type of the container. For example, the above | |
2021 | example could be rewritten as | |
2022 | ||
2023 | @snippet example/tutorial/containers.cpp overloading | |
2024 | ||
2025 | This way, the second overload of `f` will only match when `R` is a type whose | |
2026 | tag is `range_tag`, regardless of the exact representation of that range. Of | |
2027 | course, `is_a` can be used with any kind of container: `tuple`, `map`, `set` | |
2028 | and so on. | |
2029 | ||
2030 | ||
2031 | @subsection tutorial-containers-elements Container elements | |
2032 | ||
2033 | In Hana, containers own their elements. When a container is created, it makes | |
2034 | a _copy_ of the elements used to initialize it and stores them inside the | |
2035 | container. Of course, unnecessary copies are avoided by using move semantics. | |
2036 | Because of those owning semantics, the lifetime of the objects inside the | |
2037 | container is the same as that of the container. | |
2038 | ||
2039 | @snippet example/tutorial/containers.cpp lifetime | |
2040 | ||
2041 | Much like containers in the standard library, containers in Hana expect their | |
2042 | elements to be objects. For this reason, references _may not_ be stored in | |
2043 | them. When references must be stored inside a container, one should use a | |
2044 | `std::reference_wrapper` instead: | |
2045 | ||
2046 | @snippet example/tutorial/containers.cpp reference_wrapper | |
2047 | ||
2048 | ||
2049 | ||
2050 | ||
2051 | ||
2052 | ||
2053 | ||
2054 | ||
2055 | ||
2056 | ||
2057 | @section tutorial-algorithms Generalities on algorithms | |
2058 | ||
2059 | ------------------------------------------------------------------------------ | |
2060 | Much like the previous section introduced general but important notions about | |
2061 | heterogeneous containers, this section introduces general notions about | |
2062 | heterogeneous algorithms. | |
2063 | ||
2064 | ||
2065 | @subsection tutorial-algorithms-value By-value semantics | |
2066 | ||
2067 | Algorithms in Hana always return a new container holding the result. This | |
2068 | allows one to easily chain algorithms by simply using the result of the first | |
2069 | as the input of the second. For example, to apply a function to every element | |
2070 | of a tuple and then reverse the result, one simply has to connect the `reverse` | |
2071 | and `transform` algorithms: | |
2072 | ||
2073 | @snippet example/tutorial/algorithms.cpp reverse_transform | |
2074 | ||
2075 | This is different from the algorithms of the standard library, where one has | |
2076 | to provide iterators to the underlying sequence. For reasons documented in the | |
2077 | [rationales](@ref tutorial-rationales-iterators), an iterator-based design was | |
2078 | considered but was quickly dismissed in favor of composable and efficient | |
2079 | abstractions better suited to the very particular context of heterogeneous | |
2080 | programming. | |
2081 | ||
2082 | One might also think that returning full sequences that own their elements | |
2083 | from an algorithm would lead to tons of undesirable copies. For example, when | |
2084 | using `reverse` and `transform`, one could think that an intermediate copy is | |
2085 | made after the call to `transform`: | |
2086 | ||
2087 | @snippet example/tutorial/algorithms.cpp reverse_transform_copy | |
2088 | ||
2089 | To make sure this does not happen, Hana uses perfect forwarding and move | |
2090 | semantics heavily so it can provide an almost optimal runtime performance. | |
2091 | So instead of doing a copy, a move occurs between `reverse` and `transform`: | |
2092 | ||
2093 | @snippet example/tutorial/algorithms.cpp reverse_transform_move | |
2094 | ||
2095 | Ultimately, the goal is that code written using Hana should be equivalent to | |
2096 | clever hand-written code, except it should be enjoyable to write. Performance | |
2097 | considerations are explained in depth in their own [section] | |
2098 | (@ref tutorial-performance). | |
2099 | ||
2100 | ||
2101 | @subsection tutorial-algorithms-laziness (Non-)Laziness | |
2102 | ||
2103 | Algorithms in Hana are not lazy. When an algorithm is called, it does its | |
2104 | job and returns a new sequence containing the result, end of the story. | |
2105 | For example, calling the `permutations` algorithm on a large sequence is | |
2106 | a stupid idea, because Hana will actually compute all the permutations: | |
2107 | ||
2108 | @code{cpp} | |
2109 | auto perms = hana::permutations(hana::make_tuple(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); | |
2110 | // perms has 3 628 800 elements, and your compiler just crashed | |
2111 | @endcode | |
2112 | ||
2113 | To contrast, algorithms in Boost.Fusion return views which hold the original | |
2114 | sequence by reference and apply the algorithm on demand, as the elements of | |
2115 | the sequence are accessed. This leads to subtle lifetime issues, like having | |
2116 | a view that refers to a sequence that was destroyed. Hana's design assumes | |
2117 | that most of the time, we want to access all or almost all the elements in a | |
2118 | sequence anyway, and hence performance is not a big argument in favor of | |
2119 | laziness. | |
2120 | ||
2121 | ||
2122 | @subsection tutorial-algorithms-codegen What is generated? | |
2123 | ||
2124 | Algorithms in Hana are a bit special with respect to the runtime code they are | |
2125 | expanded into. The goal of this subsection is not to explain exactly what code | |
2126 | is generated, which depends on the compiler anyway, but to give a feel for | |
2127 | things. Basically, a Hana algorithm is like an unrolled version of an | |
2128 | equivalent classical algorithm. Indeed, since the bounds of the processed | |
2129 | sequence are known at compile-time, it makes sense that we can unroll the | |
2130 | loop over the sequence. For example, let's consider the `for_each` algorithm: | |
2131 | ||
2132 | @code{cpp} | |
2133 | auto xs = hana::make_tuple(0, 1, 2, 3); | |
2134 | hana::for_each(xs, f); | |
2135 | @endcode | |
2136 | ||
2137 | If `xs` was a runtime sequence instead of a tuple, its length would only be | |
2138 | known at runtime and the above code would have to be implemented as a loop: | |
2139 | ||
2140 | @code{cpp} | |
2141 | for (int i = 0; i < xs.size(); ++i) { | |
2142 | f(xs[i]); | |
2143 | } | |
2144 | @endcode | |
2145 | ||
2146 | However, in our case, the length of the sequence is known at compile-time and | |
2147 | so we don't have to check the index at each iteration. Hence, we can just | |
2148 | write: | |
2149 | ||
2150 | @code{cpp} | |
2151 | f(xs[0_c]); | |
2152 | f(xs[1_c]); | |
2153 | f(xs[2_c]); | |
2154 | f(xs[3_c]); | |
2155 | @endcode | |
2156 | ||
2157 | The main difference here is that no bound checking and index increment is done | |
2158 | at each step, because there is no index anymore; the loop was effectively | |
2159 | unrolled. In some cases, this can be desirable for performance reasons. In | |
2160 | other cases, this can be detrimental to performance because it causes the | |
2161 | code size to grow. As always, performance is a tricky subject and whether | |
2162 | you actually want loop unrolling to happen should be tackled on a case-by-case | |
2163 | basis. As a rule of thumb, algorithms processing all (or a subset) of the | |
2164 | elements of a container are unrolled. In fact, if you think about it, this | |
2165 | unrolling is the only way to go for heterogeneous sequences, because different | |
2166 | elements of the sequence may have different types. As you might have noticed, | |
2167 | we're not using normal indices into the tuple, but compile-time indices, which | |
2168 | can't be generated by a normal `for` loop. In other words, the following does | |
2169 | not make sense: | |
2170 | ||
2171 | @code{cpp} | |
2172 | for (??? i = 0_c; i < xs.size(); ++i) { | |
2173 | f(xs[i]); | |
2174 | } | |
2175 | @endcode | |
2176 | ||
2177 | ||
2178 | @subsection tutorial-algorithms-effects Side effects and purity | |
2179 | ||
2180 | By default, Hana assumes functions to be pure. A pure function is a function | |
2181 | that has no side-effects at all. In other words, it is a function whose effect | |
2182 | on the program is solely determined by its return value. In particular, such a | |
2183 | function may not access any state that outlives a single invocation of the | |
2184 | function. These functions have very nice properties, like the ability to | |
2185 | reason mathematically about them, to reorder or even eliminate calls, and | |
2186 | so on. Except where specified otherwise, all functions used with Hana (i.e. | |
2187 | used in higher order algorithms) should be pure. In particular, functions | |
2188 | passed to higher order algorithms are not guaranteed to be called any | |
2189 | specific number of times. Furthermore, the order of execution is generally | |
2190 | not specified and should therefore not be taken for granted. If this lack of | |
2191 | guarantees about function invocations seems crazy, consider the following use | |
2192 | of the `any_of` algorithm: | |
2193 | ||
2194 | @snippet example/tutorial/algorithms.cpp effects | |
2195 | ||
2196 | @note | |
2197 | For this to work, the external adapters for `std::integral_constant` contained | |
2198 | in `<boost/hana/ext/std/integral_constant.hpp>` must be included. | |
2199 | ||
2200 | According to the previous section on unrolling, this algorithm should be | |
2201 | expanded into something like: | |
2202 | ||
2203 | @code{cpp} | |
2204 | auto xs = hana::make_tuple("hello"s, 1.2, 3); | |
2205 | auto pred = [](auto x) { return std::is_integral<decltype(x)>{}; }; | |
2206 | ||
2207 | auto r = hana::bool_c< | |
2208 | pred(xs[0_c]) ? true : | |
2209 | pred(xs[1_c]) ? true : | |
2210 | pred(xs[2_c]) ? true : | |
2211 | false | |
2212 | >; | |
2213 | ||
2214 | BOOST_HANA_CONSTANT_CHECK(r); | |
2215 | @endcode | |
2216 | ||
2217 | Of course, the above code can't work as-is, because we're calling `pred` inside | |
2218 | something that would have to be a constant expression, but `pred` is a lambda | |
2219 | (and lambdas can't be called in constant expressions). However, whether any of | |
2220 | these objects has an integral type is clearly known at compile-time, and hence | |
2221 | we would expect that computing the answer only involves compile-time | |
2222 | computations. In fact, this is exactly what Hana does, and the above | |
2223 | algorithm is expanded into something like: | |
2224 | ||
2225 | @snippet example/tutorial/algorithms.cpp effects.codegen | |
2226 | ||
2227 | @note | |
2228 | As you will be able to deduce from the next section on cross-phase computations, | |
2229 | the implementation of `any_of` must actually be more general than this. However, | |
2230 | this [lie-to-children][] is perfect for educational purposes. | |
2231 | ||
2232 | As you can see, the predicate is never even executed; only its result type on | |
2233 | a particular object is used. Regarding the order of evaluation, consider the | |
2234 | `transform` algorithm, which is specified (for tuples) as: | |
2235 | ||
2236 | @code{cpp} | |
2237 | hana::transform(hana::make_tuple(x1, ..., xn), f) == hana::make_tuple(f(x1), ..., f(xn)) | |
2238 | @endcode | |
2239 | ||
2240 | Since `make_tuple` is a function, and since the evaluation order for the | |
2241 | arguments of a function is unspecified, the order in which `f` is called | |
2242 | on each element of the tuple is unspecified too. If one sticks to pure | |
2243 | functions, everything works fine and the resulting code is often easier | |
2244 | to understand. However, some exceptional algorithms like `for_each` do | |
2245 | expect impure functions, and they guarantee an order of evaluation. Indeed, | |
2246 | a `for_each` algorithm that would only take pure functions would be pretty | |
2247 | much useless. When an algorithm can accept an impure function or guarantees | |
2248 | some order of evaluation, the documentation for that algorithm will mention | |
2249 | it explicitly. However, by default, no guarantees may be taken for granted. | |
2250 | ||
2251 | ||
2252 | @subsection tutorial-algorithms-cross_phase Cross-phase algorithms | |
2253 | ||
2254 | This section introduces the notion of cross-phase computations and algorithms. | |
2255 | In fact, we have already used cross-phase algorithms in the [quick start] | |
2256 | (@ref tutorial-quickstart), for example with `filter`, but we did not explain | |
2257 | exactly what was happening at that time. But before we introduce cross-phase | |
2258 | algorithms, let's define what we mean by _cross-phase_. The phases we're | |
2259 | referring to here are the compilation and the execution of a program. In C++ | |
2260 | as in most statically typed languages, there is a clear distinction between | |
2261 | compile-time and runtime; this is called phase distinction. When we speak of | |
2262 | a cross-phase computation, we mean a computation that is somehow performed | |
2263 | across those phases; i.e. that is partly executed at compile-time and partly | |
2264 | executed at runtime. | |
2265 | ||
2266 | Like we saw in earlier examples, some functions are able to return something | |
2267 | that can be used at compile-time even when they are called on a runtime value. | |
2268 | For example, let's consider the `length` function applied to a non-`constexpr` | |
2269 | container: | |
2270 | ||
2271 | @snippet example/tutorial/algorithms.cpp cross_phase.setup | |
2272 | ||
2273 | Obviously, the tuple can't be made `constexpr`, since it contains runtime | |
2274 | `std::string`s. Still, even though it is not called on a constant expression, | |
2275 | `length` returns something that can be used at compile-time. If you think of | |
2276 | it, the size of the tuple is known at compile-time regardless of its content, | |
2277 | and hence it would only make sense for this information to be available to us | |
2278 | at compile-time. If that seems surprising, think about `std::tuple` and | |
2279 | `std::tuple_size`: | |
2280 | ||
2281 | @snippet example/tutorial/algorithms.cpp cross_phase.std::tuple_size | |
2282 | ||
2283 | Since the size of the tuple is encoded in its type, it is always available | |
2284 | at compile-time regardless of whether the tuple is `constexpr` or not. In Hana, | |
2285 | this is implemented by having `length` return an `IntegralConstant`. Since an | |
2286 | `IntegralConstant`'s value is encoded in its type, the result of `length` is | |
2287 | contained in the type of the object it returns, and the length is therefore | |
2288 | known at compile-time. Because `length` goes from a runtime value (the | |
2289 | container) to a compile-time value (the `IntegralConstant`), `length` is a | |
2290 | trivial example of a cross-phase algorithm (trivial because it does not really | |
2291 | manipulate the tuple). Another algorithm that is very similar to `length` is | |
2292 | the `is_empty` algorithm, which returns whether a container is empty: | |
2293 | ||
2294 | @snippet example/tutorial/algorithms.cpp cross_phase.is_empty | |
2295 | ||
2296 | More generally, any algorithm that takes a container whose value is known at | |
2297 | runtime but queries something that can be known at compile-time should be able | |
2298 | to return an `IntegralConstant` or another similar compile-time value. Let's | |
2299 | make things slightly more complicated by considering the `any_of` algorithm, | |
2300 | which we already encountered in the previous section: | |
2301 | ||
2302 | @snippet example/tutorial/algorithms.cpp cross_phase.any_of_runtime | |
2303 | ||
2304 | In this example, the result can't be known at compile-time, because the | |
2305 | predicate returns a `bool` that is the result of comparing two `std::string`s. | |
2306 | Since `std::string`s can't be compared at compile-time, the predicate must | |
2307 | operate at runtime, and the overall result of the algorithm can then only be | |
2308 | known at runtime too. However, let's say we used `any_of` with the following | |
2309 | predicate instead: | |
2310 | ||
2311 | @snippet example/tutorial/algorithms.cpp cross_phase.any_of_compile_time | |
2312 | ||
2313 | @note | |
2314 | For this to work, the external adapters for `std::integral_constant` contained | |
2315 | in `<boost/hana/ext/std/integral_constant.hpp>` must be included. | |
2316 | ||
2317 | First, since the predicate is only querying information about the type of each | |
2318 | element of the tuple, it is clear that its result can be known at compile-time. | |
2319 | Since the number of elements in the tuple is also known at compile-time, the | |
2320 | overall result of the algorithm can, in theory, be known at compile-time. More | |
2321 | precisely, what happens is that the predicate returns a value initialized | |
2322 | `std::is_same<...>`, which inherits from `std::integral_constant`. Hana | |
2323 | recognizes these objects, and the algorithm is written in such a way that it | |
2324 | preserves the `compile-time`ness of the predicate's result. In the end, | |
2325 | `any_of` hence returns an `IntegralConstant` holding the result of the | |
2326 | algorithm, and we use the compiler's type deduction in a clever way to make | |
2327 | it look easy. Hence, it would be equivalent to write (but then you would need | |
2328 | to already know the result of the algorithm!): | |
2329 | ||
2330 | @snippet example/tutorial/algorithms.cpp cross_phase.any_of_explicit | |
2331 | ||
2332 | Ok, so some algorithms are able to return compile-time values when their input | |
2333 | satisfies some constraints with respect to `compile-time`ness. However, other | |
2334 | algorithms are more restrictive and they _require_ their inputs to satisfy some | |
2335 | constraints regarding `compile-time`ness, without which they are not able to | |
2336 | operate at all. An example of this is `filter`, which takes a sequence and a | |
2337 | predicate, and returns a new sequence containing only those elements for which | |
2338 | the predicate is satisfied. `filter` requires the predicate to return an | |
2339 | `IntegralConstant`. While this requirement may seem stringent, it really makes | |
2340 | sense if you think about it. Indeed, since we're removing some elements from | |
2341 | the heterogeneous sequence, the type of the resulting sequence depends on the | |
2342 | result of the predicate. Hence, the result of the predicate has to be known at | |
2343 | compile-time for the compiler to be able to assign a type to the returned | |
2344 | sequence. For example, consider what happens when we try to filter a | |
2345 | heterogeneous sequence as follows: | |
2346 | ||
2347 | @code{cpp} | |
2348 | auto animals = hana::make_tuple(Fish{"Nemo"}, Cat{"Garfield"}, Dog{"Snoopy"}); | |
2349 | ||
2350 | auto no_garfield = hana::filter(animals, [](auto animal) { | |
2351 | return animal.name != "Garfield"s; | |
2352 | }); | |
2353 | @endcode | |
2354 | ||
2355 | Clearly, we know that the predicate will only return false on the second | |
2356 | element, and hence the result _should be_ a `[Fish, Dog]` tuple. However, | |
2357 | the compiler has no way of knowing this since the predicate's result is the | |
2358 | result of a runtime computation, which happens way after the compiler has | |
2359 | finished its job. Hence, the compiler does not have enough information to | |
2360 | determine the return type of the algorithm. However, we could `filter` the | |
2361 | same sequence with any predicate whose result is available at compile-time: | |
2362 | ||
2363 | @snippet example/tutorial/algorithms.cpp cross_phase.filter | |
2364 | ||
2365 | Since the predicate returns an `IntegralConstant`, we know which elements | |
2366 | of the heterogeneous sequence we'll be keeping at compile-time. Hence, the | |
2367 | compiler is able to figure out the return type of the algorithm. Other | |
2368 | algorithms like `partition` and `sort` work similarly; special algorithm | |
2369 | requirements are always documented, just read the reference documentation | |
2370 | of an algorithm before using it to avoid surprises. | |
2371 | ||
2372 | This is the end of the section on algorithms. While this constitutes a fairly | |
2373 | complete explanation of phase interaction inside algorithms, a deeper | |
2374 | understanding can be gained by reading the [advanced section] | |
2375 | (@ref tutorial-appendix-constexpr) on `constexpr` and the reference | |
2376 | for `Constant` and `IntegralConstant`. | |
2377 | ||
2378 | ||
2379 | @warning | |
2380 | Hana's algorithms are `constexpr` function objects instead of being template | |
2381 | functions. This allows passing them to higher-order algorithms, which is very | |
2382 | useful. However, since those function objects are defined at namespace scope | |
2383 | in the header files, this causes each translation unit to see a different | |
2384 | algorithm object. Hence, the address of an algorithm function object is not | |
2385 | guaranteed to be unique across translation units, which can cause an ODR | |
2386 | violation if one relies on such an address. So, in short, do not rely on the | |
2387 | uniqueness of the address of any global object provided by Hana, which does | |
2388 | not make sense in the general case anyway because such objects are `constexpr`. | |
2389 | See [issue #76](https://github.com/boostorg/hana/issues/76) for more information. | |
2390 | ||
2391 | ||
2392 | ||
2393 | ||
2394 | ||
2395 | ||
2396 | ||
2397 | ||
2398 | ||
2399 | ||
2400 | @section tutorial-performance Performance considerations | |
2401 | ||
2402 | ------------------------------------------------------------------------------ | |
2403 | C++ programmers love performance, so here's a whole section dedicated to it. | |
2404 | Since Hana lives on the frontier between runtime and compile-time computations, | |
2405 | we are not only interested in runtime performance, but also compile-time | |
2406 | performance. Since both topics are pretty much disjoint, we treat them | |
2407 | separately below. | |
2408 | ||
2409 | @note | |
2410 | The benchmarks presented in this section are updated automatically when we | |
2411 | push to the repository. If you notice results that do not withstand the | |
2412 | claims made here, open a [GitHub issue][Hana.issues]; it could be a | |
2413 | performance regression. | |
2414 | ||
2415 | @warning | |
2416 | As of writing this, not all of Hana's containers are optimized. Implementing | |
2417 | Hana was a big enough challenge that containers were initially written naively | |
2418 | and are now in the process of being rigorously optimized. In particular, the | |
2419 | associative containers (`hana::map` and `hana::set`) have a pretty bad | |
2420 | compile-time behavior because of their naive implementation, and their runtime | |
2421 | behavior also seems to be problematic in some cases. Improving this situation | |
2422 | is in the TODO list. | |
2423 | ||
2424 | ||
2425 | @subsection tutorial-performance-compile Compile-time performance | |
2426 | ||
2427 | C++ metaprogramming brings its share of awful things. One of the most annoying | |
2428 | and well-known problem associated to it is interminable compilation times. | |
2429 | Hana claims to be more compile-time efficient than its predecessors; this is | |
2430 | a bold claim and we will now try to back it. Of course, Hana can't do miracles; | |
2431 | metaprogramming is a byproduct of the C++ template system and the compiler is | |
2432 | not meant to be used as an interpreter for some meta language. However, by | |
2433 | using cutting edge and intensely benchmarked techniques, Hana is able to | |
2434 | minimize the strain on the compiler. | |
2435 | ||
2436 | @note | |
2437 | While Hana has better compile-times than pre-C++11 metaprogramming libraries, | |
2438 | modern libraries supporting only type-level computations (such as [Brigand][]) | |
2439 | can provide better compile-times, at the cost of generality. Indeed, Hana's | |
2440 | ability to manipulate runtime values comes at a compile-time cost, no matter | |
2441 | how hard we try to mitigate it. If you want to use Hana for intensive type-level | |
2442 | computations, you should benchmark and see whether it suits you. | |
2443 | ||
2444 | Before we dive, let me make a quick note on the methodology used to measure | |
2445 | compile-time performance in Hana. Previous metaprogramming libraries measured | |
2446 | the compile-time complexity of their meta-algorithms and meta-sequences by | |
2447 | looking at the number of instantiations the compiler had to perform. While | |
2448 | easy to understand, this way of measuring the compile-time complexity actually | |
2449 | does not give us a lot of information regarding the compilation time, which | |
2450 | is what we're interested in minimizing at the end of the day. Basically, the | |
2451 | reason for this is that template metaprogramming is such a twisted model of | |
2452 | computation that it's very hard to find a standard way of measuring the | |
2453 | performance of algorithms. Hence, instead of presenting meaningless complexity | |
2454 | analyses, we prefer to benchmark everything on every supported compiler and to | |
2455 | pick the best implementation on that compiler. Also note that the benchmarks | |
2456 | we present here are quite precise. Indeed, even though we do not take multiple | |
2457 | measurements and take their mean or something similar to reduce incertitude, | |
2458 | the benchmarks are very stable when they are regenerated, which suggests a | |
2459 | reasonably good precision. Now, let's dive. | |
2460 | ||
2461 | First, Hana minimizes its dependency on the preprocessor. In addition to | |
2462 | yielding cleaner error messages in many cases, this reduces the overall | |
2463 | parsing and preprocessing time for header files. Also, because Hana only | |
2464 | supports cutting edge compilers, there are very few workarounds in the | |
2465 | library, which results in a cleaner and smaller library. Finally, Hana | |
2466 | minimizes reliance on any kind of external dependencies. In particular, | |
2467 | it only uses other Boost libraries in a few specific cases, and it does | |
2468 | not rely on the standard library for the largest part. There are several | |
2469 | reasons (other than include times) for doing so; they are documented in | |
2470 | the [rationales](@ref tutorial-rationales-dependencies). | |
2471 | ||
2472 | Below is a chart showing the time required to include different libraries. The | |
2473 | chart shows the time for including everything in the (non-external) public API | |
2474 | of each library. For example, for Hana this means the `<boost/hana.hpp>` header, | |
2475 | which excludes the external adapters. For other libraries like Boost.Fusion, | |
2476 | this means including all the public headers in the `boost/fusion/` directory, | |
2477 | but not the adapters for external libraries like the MPL. | |
2478 | ||
2479 | <div class="benchmark-chart" | |
2480 | style="min-width: 310px; height: 400px; margin: 0 auto" | |
2481 | data-dataset="benchmark.including.compile.json"> | |
2482 | </div> | |
2483 | ||
2484 | In addition to reduced preprocessing times, Hana uses modern techniques to | |
2485 | implement heterogeneous sequences and algorithms in the most compile-time | |
2486 | efficient way possible. Before jumping to the compile-time performance of | |
2487 | the algorithms, we will have a look at the compile-time cost of creating | |
2488 | heterogeneous sequences. Indeed, since we will be presenting algorithms that | |
2489 | work on sequences, we must be aware of the cost of creating the sequences | |
2490 | themselves, since that will influence the benchmarks for the algorithms. | |
2491 | The following chart presents the compile-time cost of creating a sequence | |
2492 | of `n` heterogeneous elements. | |
2493 | ||
2494 | <div class="benchmark-chart" | |
2495 | style="min-width: 310px; height: 400px; margin: 0 auto" | |
2496 | data-dataset="benchmark.make.compile.json"> | |
2497 | </div> | |
2498 | ||
2499 | @note | |
2500 | You can zoom on the chart by selecting an area to zoom into. Also, you can | |
2501 | hide a series of points by clicking on it in the legend on the right. | |
2502 | ||
2503 | The benchmark methodology is to always create the sequences in the most | |
2504 | efficient way possible. For Hana and `std::tuple`, this simply means using | |
2505 | the appropriate `make_tuple` function. However, for the MPL, this means | |
2506 | creating a `mpl::vectorN` of size up to 20, and then using `mpl::push_back` | |
2507 | to create larger vectors. We use a similar technique for Fusion sequences. | |
2508 | The reason for doing so is that Fusion and MPL sequences have fixed size | |
2509 | limits, and the techniques used here have been found to be the fastest way | |
2510 | to create longer sequences. | |
2511 | ||
2512 | For completeness, we also present the compile-time cost of creating a | |
2513 | `std::array` with `n` elements. However, note that `std::array` can only | |
2514 | hold elements with a single type, so we're comparing apples and oranges | |
2515 | here. As you can see, the cost of creating a `std::array` is constant and | |
2516 | essentially inexistent (the non-zero overhead is that of simply including | |
2517 | the `<array>` header). Hence, while Hana provides improved compile-times | |
2518 | over other heterogeneous containers, please stick with normal homogeneous | |
2519 | containers if that's all you need for your application; your compile-times | |
2520 | will be much faster that way. | |
2521 | ||
2522 | You can also see that creating sequences has a non-negligible cost. Actually, | |
2523 | this is really the most expensive part of doing heterogeneous computations, | |
2524 | as you will see in the following charts. Hence, when you look at the charts | |
2525 | below, keep in mind the cost of merely creating the sequences. Also note that | |
2526 | only the most important algorithms will be presented here, but the [Metabench][] | |
2527 | project provides micro benchmarks for compile-time performance for almost all | |
2528 | of Hana's algorithms. Also, the benchmarks we present compare several different | |
2529 | libraries. However, since Hana and Fusion can work with values and not only | |
2530 | types, comparing their algorithms with type-only libraries like MPL is not | |
2531 | really fair. Indeed, Hana and Fusion algorithms are more powerful since they | |
2532 | also allow runtime effects to be performed. However, the comparison between | |
2533 | Fusion and Hana is fair, because both libraries are just as powerful (strictly | |
2534 | speaking). Finally, we can't show benchmarks of the algorithms for `std::tuple`, | |
2535 | because the standard does not provide equivalent algorithms. Of course, we | |
2536 | could use Hana's external adapters, but that would not be a faithful comparison. | |
2537 | ||
2538 | The first algorithm which is ubiquitous in metaprogramming is `transform`. | |
2539 | It takes a sequence and a function, and returns a new sequence containing the | |
2540 | result of applying the function to each element. The following chart presents | |
2541 | the compile-time performance of applying `transform` to a sequence of `n` | |
2542 | elements. The `x` axis represents the number of elements in the sequence, and | |
2543 | the `y` axis represents the compilation time in seconds. Also note that we're | |
2544 | using the `transform` equivalent in each library; we're not using Hana's | |
2545 | `transform` through the Boost.Fusion adapters, for example, because we really | |
2546 | want to benchmark their implementation against ours. | |
2547 | ||
2548 | <div class="benchmark-chart" | |
2549 | style="min-width: 310px; height: 400px; margin: 0 auto" | |
2550 | data-dataset="benchmark.transform.compile.json"> | |
2551 | </div> | |
2552 | ||
2553 | Here, we can see that Hana's tuple performs better than all the other | |
2554 | alternatives. This is mainly due to the fact that we use C++11 variadic | |
2555 | parameter pack expansion to implement this algorithm under the hood, which | |
2556 | is quite efficient. | |
2557 | ||
2558 | Before we move on, it is important to mention something regarding the benchmark | |
2559 | methodology for Fusion algorithms. Some algorithms in Fusion are lazy, which | |
2560 | means that they don't actually perform anything, but simply return a modified | |
2561 | view to the original data. This is the case of `fusion::transform`, which | |
2562 | simply returns a transformed view that applies the function to each element | |
2563 | of the original sequence as those elements are accessed. If we want to | |
2564 | benchmark anything at all, we need to force the evaluation of that view, as | |
2565 | would eventually happen when accessing the elements of the sequence in real | |
2566 | code. However, for complex computations with multiple layers, a lazy approach | |
2567 | may yield a substantially different compile-time profile. Of course, this | |
2568 | difference is poorly represented in micro benchmarks, so keep in mind that | |
2569 | these benchmarks only give a part of the big picture. For completeness in the | |
2570 | rest of the section, we will mention when a Fusion algorithm is lazy, so that | |
2571 | you know when we're _artificially_ forcing the evaluation of the algorithm for | |
2572 | the purpose of benchmarking. | |
2573 | ||
2574 | @note | |
2575 | We are currently considering adding lazy views to Hana. If this feature is | |
2576 | important to you, please let us know by commenting | |
2577 | [this issue](https://github.com/boostorg/hana/issues/193). | |
2578 | ||
2579 | The second important class of algorithms are folds. Folds can be used to | |
2580 | implement many other algorithms like `count_if`, `minimum` and so on. | |
2581 | Hence, a good compile-time performance for fold algorithms ensures a good | |
2582 | compile-time performance for those derived algorithms, which is why we're | |
2583 | only presenting folds here. Also note that all the non-monadic fold variants | |
2584 | are somewhat equivalent in terms of compile-time, so we only present the left | |
2585 | folds. The following chart presents the compile-time performance of applying | |
2586 | `fold_left` to a sequence of `n` elements. The `x` axis represents the number | |
2587 | of elements in the sequence, and the `y` axis represents the compilation time | |
2588 | in seconds. The function used for folding is a dummy function that does nothing. | |
2589 | In real code, you would likely fold with a nontrivial operation, so the curves | |
2590 | would be worse than that. However, these are micro benchmarks and hence they | |
2591 | only show the performance of the algorithm itself. | |
2592 | ||
2593 | <div class="benchmark-chart" | |
2594 | style="min-width: 310px; height: 400px; margin: 0 auto" | |
2595 | data-dataset="benchmark.fold_left.compile.json"> | |
2596 | </div> | |
2597 | ||
2598 | The third and last algorithm that we present here is the `find_if` algorithm. | |
2599 | This algorithm is difficult to implement efficiently, because it requires | |
2600 | stopping at the first element which satisfies the given predicate. For the | |
2601 | same reason, modern techniques don't really help us here, so this algorithm | |
2602 | constitutes a good test of the implementation quality of Hana, without taking | |
2603 | into account the free lunch given to use by C++14. | |
2604 | ||
2605 | <div class="benchmark-chart" | |
2606 | style="min-width: 310px; height: 400px; margin: 0 auto" | |
2607 | data-dataset="benchmark.find_if.compile.json"> | |
2608 | </div> | |
2609 | ||
2610 | As you can see, Hana performs better than Fusion, and as well as MPL, yet | |
2611 | Hana's `find_if` can be used with values too, unlike MPL's. This concludes | |
2612 | the section on compile-time performance. In case you want to see the | |
2613 | performance of an algorithm that we have not presented here, the [Metabench][] | |
2614 | project provides compile-time benchmarks for most of Hana's algorithms. | |
2615 | ||
2616 | ||
2617 | @subsection tutorial-performance-runtime Runtime performance | |
2618 | ||
2619 | Hana was designed to be very efficient at runtime. But before we dive into the | |
2620 | details, let's clarify one thing. Hana being a metaprogramming library which | |
2621 | allows manipulating both types and values, it does not always make sense to | |
2622 | even talk about runtime performance. Indeed, for type-level computations and | |
2623 | computations on `IntegralConstant`s, runtime performance is simply not a | |
2624 | concern, because the result of the computation is contained in a _type_, which | |
2625 | is a purely compile-time entity. In other words, these computations involve | |
2626 | only compile-time work, and no code is even generated to perform these | |
2627 | computations at runtime. The only case where it makes sense to discuss runtime | |
2628 | performance is when manipulating runtime values in heterogeneous containers | |
2629 | and algorithms, because this is the only case where the compiler has to | |
2630 | generate some runtime code. It is therefore only computations of this sort | |
2631 | that we will be studying in the remainder of this section. | |
2632 | ||
2633 | Like we did for compile-time benchmarks, the methodology used to measure | |
2634 | runtime performance in Hana is data driven rather than analytical. In other | |
2635 | words, instead of trying to determine the complexity of an algorithm by | |
2636 | counting the number of basic operations it does as a function of the input | |
2637 | size, we simply take measurements for the most interesting cases and see how | |
2638 | it behaves. There are a couple of reasons for doing so. First, we do not | |
2639 | expect Hana's algorithms to be called on large inputs since those algorithms | |
2640 | work on heterogeneous sequences whose length must be known at compile-time. | |
2641 | For example, if you tried to call the `find_if` algorithm on a sequence of | |
2642 | 100k elements, your compiler would simply die while trying to generate the | |
2643 | code for this algorithm. Hence, algorithms can't be called on very large inputs | |
2644 | and the analytical approach then loses a lot of its attractiveness. Secondly, | |
2645 | processors have evolved into pretty complex beasts, and the actual performance | |
2646 | you'll be able to squeeze out is actually controlled by much more than the | |
2647 | mere number of steps your algorithm is doing. For example, bad cache behavior | |
2648 | or branch misprediction could turn a theoretically efficient algorithm into a | |
2649 | slowpoke, especially for small inputs. Since Hana causes a lot of unrolling to | |
2650 | happen, these factors must be considered even more carefully and any analytical | |
2651 | approach would probably only comfort us into thinking we're efficient. Instead, | |
2652 | we want hard data, and pretty charts to display it! | |
2653 | ||
2654 | @note | |
2655 | Like for compile-time performance, we're forcing the evaluation of some Fusion | |
2656 | algorithms that are normally lazy. Again, depending on the complexity of the | |
2657 | computation, a lazy algorithm may cause substantially different code to be | |
2658 | generated or a different design to be used, for better or worse. Keep this | |
2659 | in mind when you look at these runtime benchmarks. If performance is absolutely | |
2660 | critical to your application, you should profile _before_ and _after_ switching | |
2661 | from Fusion to Hana. And let us know if Hana performs worse; we'll fix it! | |
2662 | ||
2663 | There are a couple of different aspects we will want to benchmark. First, we | |
2664 | will obviously want to benchmark the execution time of the algorithms. | |
2665 | Secondly, because of the by-value semantics used throughout the library, we | |
2666 | will also want to make sure that the minimum amount of data is copied around. | |
2667 | Finally, we will want to make sure that using Hana does not cause too much | |
2668 | code bloat because of unrolling, as explained in the [section] | |
2669 | (@ref tutorial-algorithms-codegen) on algorithms. | |
2670 | ||
2671 | Just like we studied only a couple of key algorithms for compile-time | |
2672 | performance, we will focus on the runtime performance of a few algorithms. | |
2673 | For each benchmarked aspect, we will compare the algorithm as implemented by | |
2674 | different libraries. Our goal is to always be at least as efficient as | |
2675 | Boost.Fusion, which is near from optimality in terms of runtime performance. | |
2676 | For comparison, we also show the same algorithm as executed on a runtime | |
2677 | sequence, and on a sequence whose length is known at compile-time but whose | |
2678 | `transform` algorithm does not use explicit loop unrolling. All the benchmarks | |
2679 | presented here are done in a _Release_ CMake configuration, which takes care | |
2680 | of passing the proper optimization flags (usually `-O3`). Let's start with the | |
2681 | following chart, which shows the execution time required to `transform` | |
2682 | different kinds of sequences: | |
2683 | ||
2684 | <div class="benchmark-chart" | |
2685 | style="min-width: 310px; height: 400px; margin: 0 auto" | |
2686 | data-dataset="benchmark.transform.execute.json"> | |
2687 | </div> | |
2688 | ||
2689 | @note | |
2690 | Keep in mind that `fusion::transform` is usually lazy, and we're forcing its | |
2691 | evaluation for the purpose of benchmarking. | |
2692 | ||
2693 | As you can see, Hana and Fusion are pretty much on the same line. `std::array` | |
2694 | is slightly slower for larger collections data sets, and `std::vector` is | |
2695 | noticeably slower for larger collections. Since we also want to look out for | |
2696 | code bloat, let's take a look at the size of the executable generated for the | |
2697 | exact same scenario: | |
2698 | ||
2699 | <div class="benchmark-chart" | |
2700 | style="min-width: 310px; height: 400px; margin: 0 auto" | |
2701 | data-dataset="benchmark.transform.bloat.json"> | |
2702 | </div> | |
2703 | ||
2704 | As you can see, code bloat does not seem to be an issue, at least not one that | |
2705 | can be detected in micro benchmarks such as this one. Let's now take a look at | |
2706 | the `fold` algorithm, which is used very frequently: | |
2707 | ||
2708 | <div class="benchmark-chart" | |
2709 | style="min-width: 310px; height: 400px; margin: 0 auto" | |
2710 | data-dataset="benchmark.fold_left.execute.json"> | |
2711 | </div> | |
2712 | ||
2713 | Here, you can see that everybody is performing pretty much the same, which | |
2714 | is a good sign that Hana is at least not screwing things up. | |
2715 | Again, let's look at the executable size: | |
2716 | ||
2717 | <div class="benchmark-chart" | |
2718 | style="min-width: 310px; height: 400px; margin: 0 auto" | |
2719 | data-dataset="benchmark.fold_left.bloat.json"> | |
2720 | </div> | |
2721 | ||
2722 | Here again, the code size did not explode. So at least for moderate usages of | |
2723 | Hana (and Fusion for that matter, since they have the same problem), code | |
2724 | bloat should not be a major concern. The containers in the charts we just | |
2725 | presented contain randomly generated `int`s, which is cheap to copy around and | |
2726 | lends itself well to micro benchmarks. However, what happens when we chain | |
2727 | multiple algorithms on a container whose elements are expensive to copy? More | |
2728 | generally, the question is: when an algorithm is passed a temporary object, | |
2729 | does it seize the opportunity to avoid unnecessary copies? Consider: | |
2730 | ||
2731 | @code{cpp} | |
2732 | auto xs = hana::make_tuple("some"s, "huge"s, "string"s); | |
2733 | ||
2734 | // No copy of xs's elements should be made: they should only be moved around. | |
2735 | auto ys = hana::reverse(std::move(xs)); | |
2736 | @endcode | |
2737 | ||
2738 | To answer this question, we'll look at the chart generated when benchmarking | |
2739 | the above code for strings of about 1k characters. However, note that it does | |
2740 | not really make sense to benchmark this for standard library algorithms, | |
2741 | because they do not return containers. | |
2742 | ||
2743 | <div class="benchmark-chart" | |
2744 | style="min-width: 310px; height: 400px; margin: 0 auto" | |
2745 | data-dataset="benchmark.reverse.move.json"> | |
2746 | </div> | |
2747 | ||
2748 | @note | |
2749 | Keep in mind that `fusion::reverse` is usually lazy, and we're forcing its | |
2750 | evaluation for the purpose of benchmarking. | |
2751 | ||
2752 | As you can see, Hana is faster than Fusion, probably because of a more | |
2753 | consistent use of move semantics in the implementation. If we had not | |
2754 | provided a temporary container to `reverse`, no move could have been | |
2755 | performed by Hana and both libraries would have performed similarly: | |
2756 | ||
2757 | <div class="benchmark-chart" | |
2758 | style="min-width: 310px; height: 400px; margin: 0 auto" | |
2759 | data-dataset="benchmark.reverse.nomove.json"> | |
2760 | </div> | |
2761 | ||
2762 | This concludes the section on runtime performance. Hopefully you are now | |
2763 | convinced that Hana was built for speed. Performance is important to us: | |
2764 | if you ever encounter a scenario where Hana causes bad code to be generated | |
2765 | (and the fault is not on the compiler), please open an [issue][Hana.issues] | |
2766 | so the problem can be addressed. | |
2767 | ||
2768 | ||
2769 | ||
2770 | ||
2771 | ||
2772 | ||
2773 | ||
2774 | ||
2775 | ||
2776 | ||
2777 | @section tutorial-ext Integration with external libraries | |
2778 | ||
2779 | ------------------------------------------------------------------------------ | |
2780 | ||
2781 | Hana provides out-of-the-box integration with some existing libraries. | |
2782 | Specifically, this means that you can use some containers from these | |
2783 | libraries in Hana's algorithms by simply including the appropriate header | |
2784 | making the bridge between Hana and the external component. This can be | |
2785 | very useful for porting existing code from e.g. Fusion/MPL to Hana: | |
2786 | ||
2787 | @snippet example/tutorial/ext/fusion_to_hana.cpp main | |
2788 | ||
2789 | @note | |
2790 | At this time, only adapters to use data types from other libraries inside Hana | |
2791 | are provided; adapters for the other way around (using Hana containers inside | |
2792 | other libraries) are not provided. | |
2793 | ||
2794 | However, using external adapters has a couple of pitfalls. For example, after | |
2795 | a while using Hana, you might become used to comparing Hana tuples using the | |
2796 | normal comparison operators, or doing arithmetic with Hana `integral_constant`s. | |
2797 | Of course, nothing guarantees that these operators are defined for external | |
2798 | adapters too (and in general they won't be). Hence, you'll have to stick to | |
2799 | the functions provided by Hana that implement these operators. For example: | |
2800 | ||
2801 | @code{cpp} | |
2802 | auto r = std::ratio<3, 4>{} + std::ratio<4, 5>{}; // error, the operator is not defined! | |
2803 | @endcode | |
2804 | ||
2805 | Instead, you should use the following: | |
2806 | ||
2807 | @snippet example/tutorial/ext/ratio_plus.cpp main | |
2808 | ||
2809 | But sometimes, it's much worse. Some external components define operators, but | |
2810 | they don't necessarily have the same semantics as those from Hana. For example, | |
2811 | comparing two `std::tuple`s of different lengths will give an error when using | |
2812 | `operator==`: | |
2813 | ||
2814 | @code{cpp} | |
2815 | std::make_tuple(1, 2, 3) == std::make_tuple(1, 2); // compiler error | |
2816 | @endcode | |
2817 | ||
2818 | On the other hand, comparing Hana tuples of different lengths will just return | |
2819 | a false `IntegralConstant`: | |
2820 | ||
2821 | @code{cpp} | |
2822 | hana::make_tuple(1, 2, 3) == hana::make_tuple(1, 2); // hana::false_c | |
2823 | @endcode | |
2824 | ||
2825 | This is because `std::tuple` defines its own operators, and their semantics | |
2826 | are different from that of Hana's operators. The solution is to stick with | |
2827 | Hana's named functions instead of using operators when you know you'll have | |
2828 | to work with other libraries: | |
2829 | ||
2830 | @code{cpp} | |
2831 | hana::equal(std::make_tuple(1, 2, 3), std::make_tuple(1, 2)); // hana::false_c | |
2832 | @endcode | |
2833 | ||
2834 | When using external adapters, one should also be careful not to forget | |
2835 | including the proper bridge headers. For example, suppose I want to use | |
2836 | a Boost.MPL vector with Hana. I include the appropriate bridge header: | |
2837 | ||
2838 | @snippet example/tutorial/ext/mpl_vector.cpp front | |
2839 | ||
2840 | @note | |
2841 | The exact layout of these bridge headers is documented in the section about | |
2842 | [Header organization](@ref tutorial-header_organization). | |
2843 | ||
2844 | Now, however, suppose that I use `mpl::size` to query the size of the vector | |
2845 | and then compare it to some value. I could also use `hana::length` and | |
2846 | everything would be fine, but bear with me for the sake of the example: | |
2847 | ||
2848 | @snippet example/tutorial/ext/mpl_vector.cpp size | |
2849 | ||
2850 | The reason why this breaks is that `mpl::size` returns a MPL IntegralConstant, | |
2851 | and Hana has no way of knowing about these unless you include the proper | |
2852 | bridge header. Hence, you should do the following instead: | |
2853 | ||
2854 | @snippet example/tutorial/ext/mpl_vector.cpp size-fixed | |
2855 | ||
2856 | The morale is that when working with external libraries, you have to be a bit | |
2857 | careful about what objects you are manipulating. The final pitfall is about | |
2858 | implementation limits in external libraries. Many older libraries have limits | |
2859 | regarding the maximum size of the heterogeneous containers that can be created | |
2860 | with them. For example, one may not create a Fusion list of more than | |
2861 | `FUSION_MAX_LIST_SIZE` elements in it. Obviously, these limits are inherited | |
2862 | by Hana and for example, trying to compute the permutations of a `fusion::list` | |
2863 | containing 5 elements (the resulting list would contain 120 elements) will | |
2864 | fail in a gruesome way: | |
2865 | ||
2866 | @code{cpp} | |
2867 | auto list = fusion::make_list(1, 2, 3, 4, 5); | |
2868 | auto oh_jeez = hana::permutations(list); // probably won't make it | |
2869 | @endcode | |
2870 | ||
2871 | Apart from the pitfalls explained in this section, using external adapters | |
2872 | should be just as straightforward as using normal Hana containers. Of course, | |
2873 | whenever possible, you should try to stick with Hana's containers because they | |
2874 | are usually more friendly to work with and are often more optimized. | |
2875 | ||
2876 | ||
2877 | ||
2878 | ||
2879 | ||
2880 | ||
2881 | ||
2882 | ||
2883 | ||
2884 | ||
2885 | @section tutorial-core Hana's core | |
2886 | ||
2887 | ------------------------------------------------------------------------------ | |
2888 | The goal of this section is to give a high-level overview of Hana's core. | |
2889 | This core is based on the notion of _tag_, which is borrowed from the | |
2890 | Boost.Fusion and Boost.MPL libraries but taken much further by Hana. These | |
2891 | tags are then used for several purposes, like algorithm customization, | |
2892 | documentation grouping, improving error messages and converting containers | |
2893 | into other containers. Because of its modular design, Hana can be extended | |
2894 | in a ad-hoc manner very easily. In fact, all the functionality of the library | |
2895 | is provided through an ad-hoc customization mechanism, which is explained here. | |
2896 | ||
2897 | ||
2898 | @subsection tutorial-core-tags Tags | |
2899 | ||
2900 | Heterogeneous programming is basically programming with objects having | |
2901 | different types. However, it is clear that some families of objects, while | |
2902 | having different representations (C++ types), are strongly related. For | |
2903 | example, the `std::integral_constant<int, n>` types are different for each | |
2904 | different `n`, but conceptually they all represent the same thing; a | |
2905 | compile-time number. The fact that `std::integral_constant<int, 1>{}` and | |
2906 | `std::integral_constant<int, 2>{}` have different types is just a side effect | |
2907 | of the fact that we're using their type to encode the _value_ of these objects. | |
2908 | Indeed, when manipulating a sequence of `std::integral_constant<int, ...>`s, | |
2909 | chances are that you actually think of it as a homogeneous sequence of an | |
2910 | imaginary `integral_constant` type, disregarding the actual types of the | |
2911 | objects and pretending they are all just `integral_constant`s with different | |
2912 | values. | |
2913 | ||
2914 | To reflect this reality, Hana provides _tags_ representing its heterogeneous | |
2915 | containers and other compile-time entities. For example, all of Hana's | |
2916 | `integral_constant<int, ...>`s have different types, but they all share | |
2917 | the same tag, `integral_constant_tag<int>`. This allows the programmer to | |
2918 | think in terms of that single type instead of trying to think in terms of the | |
2919 | actual types of the objects. Concretely, tags are implemented as empty `struct`s. | |
2920 | To make them stand out, Hana adopts the convention of naming these tags by | |
2921 | adding the `_tag` suffix. | |
2922 | ||
2923 | @note | |
2924 | The tag of an object of type `T` can be obtained by using `tag_of<T>::%type`, | |
2925 | or equivalently `tag_of_t<T>`. | |
2926 | ||
2927 | Tags are an extension to normal C++ types. Indeed, by default, the tag of a | |
2928 | type `T` is `T` itself, and the core of the library is designed to work in | |
2929 | those cases. For example, `hana::make` expects either a tag or an actual type; | |
2930 | if you send it a type `T`, it will do the logical thing and construct an | |
2931 | object of type `T` with the arguments you pass it. If you pass a tag to it, | |
2932 | however, you should specialize `make` for that tag and provide your own | |
2933 | implementation, as explained below. Because tags are an extension to usual | |
2934 | types, we end up mostly reasoning in terms of tags instead of usual types, | |
2935 | and the documentation sometimes uses the words _type_, _data type_ and _tag_ | |
2936 | interchangeably. | |
2937 | ||
2938 | ||
2939 | @subsection tutorial-core-tag_dispatching Tag dispatching | |
2940 | ||
2941 | Tag dispatching is a generic programming technique for picking the right | |
2942 | implementation of a function depending on the type of the arguments passed | |
2943 | to the function. The usual mechanism for overriding a function's behavior | |
2944 | is overloading. Unfortunately, this mechanism is not always convenient when | |
2945 | dealing with families of related types having different base templates, or | |
2946 | when the kind of template parameters is not known (is it a type or a non-type | |
2947 | template parameter?). For example, consider trying to overload a function for | |
2948 | all Boost.Fusion vectors: | |
2949 | ||
2950 | @code{cpp} | |
2951 | template <typename ...T> | |
2952 | void function(boost::fusion::vector<T...> v) { | |
2953 | // whatever | |
2954 | } | |
2955 | @endcode | |
2956 | ||
2957 | If you know Boost.Fusion, then you probably know that it won't work. This is | |
2958 | because Boost.Fusion vectors are not necessarily specializations of the | |
2959 | `boost::fusion::vector` template. Fusion vectors also exist in numbered | |
2960 | forms, which are all of different types: | |
2961 | ||
2962 | @code{cpp} | |
2963 | boost::fusion::vector1<T> | |
2964 | boost::fusion::vector2<T, U> | |
2965 | boost::fusion::vector3<T, U, V> | |
2966 | ... | |
2967 | @endcode | |
2968 | ||
2969 | This is an implementation detail required by the lack of variadic templates in | |
2970 | C++03 that leaks into the interface. This is unfortunate, but we need a way to | |
2971 | work around it. To do so, we use an infrastructure with three distinct | |
2972 | components: | |
2973 | ||
2974 | 1. A metafunction associating a single tag to every type in a family of | |
2975 | related types. In Hana, this tag can be accessed using the `tag_of` | |
2976 | metafunction. Specifically, for any type `T`, `tag_of<T>::%type` is | |
2977 | the tag used to dispatch it. | |
2978 | ||
2979 | 2. A function belonging to the public interface of the library, for which | |
2980 | we'd like to be able to provide a customized implementation. In Hana, | |
2981 | these functions are the algorithms associated to a concept, like | |
2982 | `transform` or `unpack`. | |
2983 | ||
2984 | 3. An implementation for the function, parameterized with the tag(s) of the | |
2985 | argument(s) passed to the function. In Hana, this is usually done by having | |
2986 | a separate template called `xxx_impl` (for an interface function `xxx`) | |
2987 | with a nested `apply` static function, as will be shown below. | |
2988 | ||
2989 | When the public interface function `xxx` is called, it will get the tag of the | |
2990 | argument(s) it wishes to dispatch the call on, and then forward the call to | |
2991 | the `xxx_impl` implementation associated to those tags. For example, let's | |
2992 | implement a basic setup for tag dispatching of a function that prints its | |
2993 | argument to a stream. First, we define the public interface function and the | |
2994 | implementation that can be specialized: | |
2995 | ||
2996 | @snippet example/tutorial/tag_dispatching.cpp setup | |
2997 | ||
2998 | Now, let's define a type that needs tag dispatching to customize the behavior | |
2999 | of `print`. While some C++14 examples exist, they are too complicated to show | |
3000 | in this tutorial and we will therefore use a C++03 tuple implemented as several | |
3001 | different types to illustrate the technique: | |
3002 | ||
3003 | @snippet example/tutorial/tag_dispatching.cpp vector | |
3004 | ||
3005 | The nested `using hana_tag = vector_tag;` part is a terse way of controling | |
3006 | the result of the `tag_of` metafunction, and hence the tag of the `vectorN` | |
3007 | type. This is explained in the reference for `tag_of`. Finally, if you wanted | |
3008 | to customize the behavior of the `print` function for all the `vectorN` types, | |
3009 | you would normally have to write something along the lines of | |
3010 | ||
3011 | @snippet example/tutorial/tag_dispatching.cpp old_way | |
3012 | ||
3013 | Now, with tag dispatching, you can rely on the `vectorN`s all sharing the same | |
3014 | tag and specialize only the `print_impl` struct instead: | |
3015 | ||
3016 | @snippet example/tutorial/tag_dispatching.cpp customize | |
3017 | ||
3018 | One upside is that all `vectorN`s can now be treated uniformly by the `print` | |
3019 | function, at the cost of some boilerplate when creating the data structure | |
3020 | (to specify the tag of each `vectorN`) and when creating the initial `print` | |
3021 | function (to setup the tag dispatching system with `print_impl`). There are | |
3022 | also other advantages to this technique, like the ability to check for | |
3023 | preconditions in the interface function without having to do it in each | |
3024 | custom implementation, which would be tedious: | |
3025 | ||
3026 | @snippet example/tutorial/tag_dispatching.cpp preconditions | |
3027 | ||
3028 | @note | |
3029 | Checking preconditions does not make much sense for a `print` function, but | |
3030 | consider for example a function to get the `n`th element of a sequence; you | |
3031 | might want to make sure that the index is not out-of-bounds. | |
3032 | ||
3033 | This technique also makes it easier to provide interface functions as function | |
3034 | objects instead of normal overloaded functions, because only the interface | |
3035 | function itself must go through the trouble of defining a function object. | |
3036 | Function objects have several advantages over overloaded functions, like the | |
3037 | ability to be used in higher order algorithms or as variables: | |
3038 | ||
3039 | @snippet example/tutorial/tag_dispatching.cpp function_objects | |
3040 | ||
3041 | As you are probably aware of, being able to implement an algorithm for many | |
3042 | types at the same time is tremendously useful (that's precisely the goal of | |
3043 | C++ templates!). However, even more useful is the ability to implement an | |
3044 | algorithm for many types _that satisfy some condition_. C++ templates are | |
3045 | currently missing this ability to constrain their template parameters, but a | |
3046 | language feature called [concepts][C++17.clite] is being rolled out with the | |
3047 | goal of addressing this issue. | |
3048 | ||
3049 | With something similar in mind, Hana's algorithms support an additional layer | |
3050 | of tag-dispatching to what was explained above. This layer allows us to | |
3051 | "specialize" an algorithm for all types that satisfy some predicate. For | |
3052 | example, let's say we wanted to implement the `print` function above for all | |
3053 | types that represent some kind of sequence. Right now, we wouldn't have an | |
3054 | easy way to do this. However, the tag dispatching for Hana's algorithms is | |
3055 | set up slightly differently than what was shown above, and we could hence | |
3056 | write the following: | |
3057 | ||
3058 | @snippet example/tutorial/tag_dispatching.cpp customize-when | |
3059 | ||
3060 | where `Tag represents some kind of sequence` would only need to be a boolean | |
3061 | expression representing whether `Tag` is a sequence. We'll see how such | |
3062 | predicates can be created in the next section, but for now let's assume that | |
3063 | it _just works_. Without going into the details of how this tag-dispatching is | |
3064 | set up, the above specialization will only be picked up when the predicate is | |
3065 | satisfied, and if no better match can be found. Hence, for example, if our | |
3066 | `vector_tag` was to satisfy the predicate, our initial implementation for | |
3067 | `vector_tag` would still be preferred over the `hana::when`-based specialization, | |
3068 | because it represents a better match. In general, any specialization (whether | |
3069 | explicit or partial) _not_ using `hana::when` will be preferred over a | |
3070 | specialization using `hana::when`, which was designed to be as unsurprising | |
3071 | as possible from a user point of view. This covers pretty much all there's | |
3072 | to say about tag-dispatching in Hana. The next section will explain how we | |
3073 | can create C++ concepts for metaprogramming, which could then be used in | |
3074 | conjunction with `hana::when` to achieve a great deal of expressiveness. | |
3075 | ||
3076 | ||
3077 | @subsection tutorial-core-concepts Emulation of C++ concepts | |
3078 | ||
3079 | The implementation of concepts in Hana is very simple. At its heart, a concept | |
3080 | is just a template `struct` with a nested `::%value` boolean representing | |
3081 | whether the given type is a _model_ of the concept: | |
3082 | ||
3083 | @code{cpp} | |
3084 | template <typename T> | |
3085 | struct Concept { | |
3086 | static constexpr bool value = whether T models Concept; | |
3087 | }; | |
3088 | @endcode | |
3089 | ||
3090 | Then, one can test whether a type `T` is a model of `Concept` by looking at | |
3091 | `Concept<T>::%value`. Simple enough, right? Now, while the way one might | |
3092 | implement the check does not have to be anything specific as far as Hana | |
3093 | is concerned, the rest of this section will explain how it is usually done | |
3094 | in Hana, and how it interacts with tag dispatching. You should then be able | |
3095 | to define your own concepts if you so desire, or at least to understand better | |
3096 | how Hana works internally. | |
3097 | ||
3098 | Usually, a concept defined by Hana will require that any model implements some | |
3099 | tag-dispatched functions. For example, the `Foldable` concept requires that | |
3100 | any model defines at least one of `hana::unpack` and `hana::fold_left`. Of | |
3101 | course, concepts usually also define semantic requirements (called laws) that | |
3102 | must be satisfied by their models, but these laws are not (and couldn't be) | |
3103 | checked by the concept. But how do we check that some functions are properly | |
3104 | implemented? For this, we'll have to slightly modify the way we defined | |
3105 | tag-dispatched methods as shown in the previous section. Let's go back to | |
3106 | our `print` example and try to define a `Printable` concept for those objects | |
3107 | that can be `print`ed. Our end goal is to have a template struct such as | |
3108 | ||
3109 | @code{cpp} | |
3110 | template <typename T> | |
3111 | struct Printable { | |
3112 | static constexpr bool value = whether print_impl<tag of T> is defined; | |
3113 | }; | |
3114 | @endcode | |
3115 | ||
3116 | To know whether `print_impl<...>` has been defined, we'll modify `print_impl` | |
3117 | so that it inherits from a special base class when it is not overridden, and | |
3118 | we'll simply check whether `print_impl<T>` inherits from that base class: | |
3119 | ||
3120 | @snippet example/tutorial/concepts.cpp special_base_class | |
3121 | ||
3122 | Of course, when we specialize `print_impl` with a custom type, we don't | |
3123 | inherit from that `special_base_class` type: | |
3124 | ||
3125 | @snippet example/tutorial/concepts.cpp special_base_class_customize | |
3126 | ||
3127 | As you can see, `Printable<T>::%value` really only checks whether the | |
3128 | `print_impl<T>` struct was specialized by a custom type. In particular, | |
3129 | it does not even check whether the nested `::%apply` function is defined | |
3130 | or if it is syntactically valid. It is assumed that if one specializes | |
3131 | `print_impl` for a custom type, the nested `::%apply` function exists and | |
3132 | is correct. If it is not, a compilation error will be triggered when one | |
3133 | tries to call `print` on an object of that type. Concepts in Hana make the | |
3134 | same assumptions. | |
3135 | ||
3136 | Since this pattern of inheriting from a special base class is quite abundant | |
3137 | in Hana, the library provides a dummy type called `hana::default_` that can be | |
3138 | used in place of `special_base_class`. Then, instead of using `std::is_base_of`, | |
3139 | one can use `hana::is_default`, which looks nicer. With this syntactic sugar, | |
3140 | the code now becomes: | |
3141 | ||
3142 | @snippet example/tutorial/concepts.cpp actual | |
3143 | ||
3144 | This is all that there's to know about the interaction between tag-dispatched | |
3145 | functions and concepts. However, some concepts in Hana do not rely solely on | |
3146 | the definition of specific tag-dispatched functions to determine if a type is | |
3147 | a model of the concept. This can happen when a concept merely introduces | |
3148 | semantic guarantees through laws and refined concepts, but no additional | |
3149 | syntactic requirements. Defining such a concept can be useful for several | |
3150 | reasons. First, it sometimes happen that an algorithm can be implemented | |
3151 | more efficiently if we can assume some semantic guarantees X or Y, so we | |
3152 | might create a concept to enforce those guarantees. Secondly, it is sometimes | |
3153 | possible to automatically define the models for several concepts when we have | |
3154 | additional semantic guarantees, which saves the user the trouble of defining | |
3155 | those models manually. For example, this is the case of the `Sequence` concept, | |
3156 | which basically adds semantic guarantees to `Iterable` and `Foldable`, and in | |
3157 | turn allows us to define the models for a myriad of concepts ranging from | |
3158 | `Comparable` to `Monad`. | |
3159 | ||
3160 | For these concepts, it is usually necessary to specialize the corresponding | |
3161 | template struct in the `boost::hana` namespace to provide a model for a custom | |
3162 | type. Doing so is like providing a seal saying that the semantic guarantees | |
3163 | required by the concept are respected by the custom type. The concepts that | |
3164 | require being explicitly specialized will document that fact. So that's it! | |
3165 | This is all that there's to know about concepts in Hana, which ends this | |
3166 | section about the core of Hana. | |
3167 | ||
3168 | ||
3169 | ||
3170 | ||
3171 | ||
3172 | ||
3173 | ||
3174 | ||
3175 | ||
3176 | ||
3177 | @section tutorial-header_organization Header organization | |
3178 | ||
3179 | ------------------------------------------------------------------------------ | |
3180 | The library is designed to be modular while keeping the number of headers that | |
3181 | must be included to get basic functionality reasonably low. The structure of | |
3182 | the library was also intentionally kept simple, because we all love simplicity. | |
3183 | What follows is a general overview of the header organization. A list of all | |
3184 | the headers provided by the library is also available in the panel on the left | |
3185 | (under the [Headers](files.html) label) in case you need more details. | |
3186 | ||
3187 | - `boost/hana.hpp`\n | |
3188 | This is the master header of the library, which includes the whole public | |
3189 | interface of the library. Note that external adapters, experimental features | |
3190 | and implementation details are not included by this header, however, since | |
3191 | some of them require additional dependencies. | |
3192 | ||
3193 | - `boost/hana/`\n | |
3194 | This is the main directory of the library containing the definitions of | |
3195 | everything provided by the library. Each algorithm and container provided | |
3196 | by the library has its own header. For a container or an algorithm named | |
3197 | `XXX`, the corresponding header is `boost/hana/XXX.hpp`. | |
3198 | ||
3199 | - `boost/hana/concept/`\n | |
3200 | This subdirectory contains the definition of Hana's concepts. These | |
3201 | headers provide a way to check whether an object is a model of the | |
3202 | corresponding concept, and they sometimes also provide default | |
3203 | implementations for other related concepts, which are documented | |
3204 | on a per-concept basis. They also include all the algorithms associated | |
3205 | to that concept. | |
3206 | ||
3207 | - `boost/hana/core/`\n | |
3208 | This subdirectory contains the machinery for tag dispatching and other | |
3209 | related utilities like `make` and `to`. | |
3210 | ||
3211 | - `boost/hana/fwd/`\n | |
3212 | This subdirectory contains the forward declaration of everything in the | |
3213 | library. It is essentially a mirror of the `boost/hana/` directory, except | |
3214 | all the headers contain only forward declarations and documentation. For | |
3215 | example, to include the `hana::tuple` container, one can use the | |
3216 | `boost/hana/tuple.hpp` header. However, if one only wants the | |
3217 | forward declaration of that container, the `boost/hana/fwd/tuple.hpp` | |
3218 | header can be used instead. Note that forward declarations for headers | |
3219 | in `boost/hana/ext/` and `boost/hana/functional/` are not provided. | |
3220 | ||
3221 | - `boost/hana/functional/`\n | |
3222 | This subdirectory contains various function objects that are often useful, | |
3223 | but that do not necessarily belong to a concept. | |
3224 | ||
3225 | - `boost/hana/ext/`\n | |
3226 | This directory contains adapters for external libraries. For a component | |
3227 | named `xxx` in a namespace `ns`, the external adapter lives in the | |
3228 | `boost/hana/ext/ns/xxx.hpp` header. For example, the external adapter | |
3229 | for `std::tuple` lives in the `boost/hana/ext/std/tuple.hpp` header, | |
3230 | while the external adapter for `boost::mpl::vector` is in | |
3231 | `boost/hana/ext/boost/mpl/vector.hpp`. | |
3232 | ||
3233 | Note that only the strict minimum required to adapt the external components | |
3234 | is included in these headers (e.g. a forward declaration). This means that | |
3235 | the definition of the external component should still be included when one | |
3236 | wants to use it. For example: | |
3237 | @snippet example/tutorial/include_ext.cpp main | |
3238 | ||
3239 | - `boost/hana/experimental/`\n | |
3240 | This directory contains experimental features that may or may not make it | |
3241 | into the library at some point, but that were deemed useful enough to be | |
3242 | made available to the public. Features in this subdirectory reside in the | |
3243 | `hana::experimental` namespace. Also, do not expect these features to be | |
3244 | stable; they may be moved, renamed, changed or removed between releases of | |
3245 | the library. These features may also require additional external dependencies; | |
3246 | each feature documents the additional dependencies it requires, if any. | |
3247 | ||
3248 | Because of the potential additional dependencies, these headers are also | |
3249 | not included by the master header of the library. | |
3250 | ||
3251 | - `boost/hana/detail/`\n | |
3252 | This directory contains utilities required internally. Nothing in `detail/` | |
3253 | is guaranteed to be stable, so you should not use it. | |
3254 | ||
3255 | ||
3256 | ||
3257 | ||
3258 | ||
3259 | ||
3260 | ||
3261 | ||
3262 | ||
3263 | ||
3264 | @section tutorial-conclusion Conclusion | |
3265 | ||
3266 | ------------------------------------------------------------------------------ | |
3267 | You now have everything you need to start using the library. From this point | |
3268 | forward, mastering the library is only a matter of understanding how to use | |
3269 | the general purpose concepts and containers provided with it, which is best | |
3270 | done by looking at the reference documentation. At some point, you will | |
3271 | probably also want to create your own concepts and data types that fit your | |
3272 | needs better; go ahead, the library was designed to be used that way. | |
3273 | ||
3274 | @subsection tutorial-conclusion-warning Fair warning: functional programming ahead | |
3275 | ||
3276 | Programming with heterogeneous objects is inherently functional -- since it is | |
3277 | impossible to modify the type of an object, a new object must be introduced | |
3278 | instead, which rules out mutation. Unlike previous metaprogramming libraries | |
3279 | whose design was modeled on the STL, Hana uses a functional style of | |
3280 | programming which is the source for a good portion of its expressiveness. | |
3281 | However, as a result, many concepts presented in the reference will be | |
3282 | unfamiliar to C++ programmers without a knowledge of functional programming. | |
3283 | The reference attempts to make these concepts approachable by using intuition | |
3284 | whenever possible, but bear in mind that the highest rewards are usually the | |
3285 | fruit of some effort. | |
3286 | ||
3287 | This finishes the tutorial part of the documentation. I hope you enjoy using | |
3288 | the library, and please consider [contributing][Hana.contributing] to make it | |
3289 | even better! | |
3290 | ||
3291 | -- Louis | |
3292 | ||
3293 | ||
3294 | ||
3295 | ||
3296 | ||
3297 | ||
3298 | ||
3299 | ||
3300 | ||
3301 | ||
3302 | @section tutorial-reference Using the reference | |
3303 | ||
3304 | ------------------------------------------------------------------------------ | |
3305 | As for most generic libraries, algorithms in Hana are documented by the | |
3306 | concept to which they belong (`Foldable`, `Iterable`, `Searchable`, `Sequence`, | |
3307 | etc...). The different containers are then documented on their own page, and | |
3308 | the concepts that they model are documented there. The concepts modeled by | |
3309 | some container defines what algorithms can be used with such a container. | |
3310 | ||
3311 | More specifically, the structure of the reference (available in the menu to | |
3312 | the left) goes as follow: | |
3313 | ||
3314 | - @ref group-core\n | |
3315 | Documentation for the core module, which contains everything needed to | |
3316 | create concepts, data types and related utilities. This is relevant | |
3317 | if you need to extend the library, but otherwise you can probably | |
3318 | ignore this. | |
3319 | ||
3320 | - @ref group-concepts\n | |
3321 | Documentation for all the concepts provided with the library. Each concept: | |
3322 | - Documents which functions must be implemented absolutely in order to | |
3323 | model that concept. The set of functions that must be provided is called | |
3324 | a _minimal complete definition_. | |
3325 | - Documents semantic constraints that any model of that concept must satisfy. | |
3326 | These constraints are usually called laws and they are expressed in a | |
3327 | semi-formal mathematical language. Of course, those laws can't be checked | |
3328 | automatically but you should still make sure you satisfy them. | |
3329 | - Documents the concept(s) it refines, if any. Sometimes, a concept is | |
3330 | powerful enough to provide a model of a concept it refines, or at least | |
3331 | the implementation for some of its associated functions. When this is the | |
3332 | case, the concept will document which functions of the refined concept it | |
3333 | provides, and how it does so. Also, it is sometimes possible that the | |
3334 | model for a refined concept is unique, in which case it can be provided | |
3335 | automatically. When this happens, it will be documented but you don't have | |
3336 | to do anything special to get that model. | |
3337 | ||
3338 | - @ref group-datatypes\n | |
3339 | Documentation for all the data structures provided with the library. Each | |
3340 | data structure documents the concept(s) it models, and how it does so. It | |
3341 | also documents the methods tied to it but not to any concept, for example | |
3342 | `maybe` for `optional`. | |
3343 | ||
3344 | - @ref group-functional\n | |
3345 | General purpose function objects that are generally useful in a purely | |
3346 | functional setting. These are currently not tied to any concept or container. | |
3347 | ||
3348 | - @ref group-ext\n | |
3349 | Documentation for all the adapters for external libraries. These adapters | |
3350 | are documented as if they were native types provided by Hana, but obviously | |
3351 | Hana only provides the compatibility layer between them and the library. | |
3352 | ||
3353 | - @ref group-config\n | |
3354 | Macros that can be used to tweak the global behavior of the library. | |
3355 | ||
3356 | - @ref group-assertions\n | |
3357 | Macros to perform various types of assertions. | |
3358 | ||
3359 | - [<b>Alphabetical index</b>](functions.html)\n | |
3360 | Alphabetical index of everything provided in the library. | |
3361 | ||
3362 | - [<b>Headers</b>](files.html)\n | |
3363 | A list of all the headers provided by the library. | |
3364 | ||
3365 | - @ref group-details\n | |
3366 | Implementation details; don't go there. Anything not documented at all or | |
3367 | documented in this group is not guaranteed to be stable. | |
3368 | ||
3369 | After you get to know Hana a bit better, it will probably happen that you just | |
3370 | want to find the reference for a precise function, concept or container. If | |
3371 | you know the name of what you're looking for, you can use the _search_ box | |
3372 | located in the upper right corner of any page of the documentation. My | |
3373 | personal experience is that this is by far the quickest way of finding | |
3374 | what you want when you already know its name. | |
3375 | ||
3376 | ||
3377 | @subsection tutorial-reference-signatures Function signatures | |
3378 | ||
3379 | As you will see in the reference, several functions provide signatures | |
3380 | documented in a semi-formal mathematical language. We are in the process | |
3381 | of documenting all functions in this way, but this may take a while. The | |
3382 | notation used is the usual mathematical notation for defining functions. | |
3383 | Specifically, a function `Return f(Arg1, ..., ArgN);` can be defined | |
3384 | equivalently using mathematical notation as | |
3385 | ||
3386 | @f[ | |
3387 | \mathtt{f} : \mathtt{Arg}_1 \times \dots \times \mathtt{Arg}_n | |
3388 | \to \mathtt{Return} | |
3389 | @f] | |
3390 | ||
3391 | However, instead of documenting the actual argument and return types of | |
3392 | functions, those signatures are written in terms of argument and return tags. | |
3393 | This is done because of the heterogeneous setting, where the actual type of | |
3394 | an object is usually pretty meaningless and does not help to reason about | |
3395 | what's being returned or taken by a function. For example, instead of | |
3396 | documenting the `equal` function for `integral_constant`s as | |
3397 | ||
3398 | @f[ | |
3399 | \mathtt{equal} : \mathtt{integral\_constant<T, n>} \times | |
3400 | \mathtt{integral\_constant<T, m>} | |
3401 | \to \mathtt{integral\_constant<bool, n == m>} | |
3402 | @f] | |
3403 | ||
3404 | which is not really helpful (as it really presents nothing but the | |
3405 | implementation), it is instead documented using `integral_constant_tag`, | |
3406 | which acts as the "type" of all `integral_constant`s. Note that since `equal` | |
3407 | is part of the `Comparable` concept, it is not _actually_ documented for | |
3408 | `hana::integral_constant` specifically, but the idea is there: | |
3409 | ||
3410 | @f[ | |
3411 | \mathtt{equal} : \mathtt{integral\_constant\_tag<T>} \times | |
3412 | \mathtt{integral\_constant\_tag<T>} | |
3413 | \to \mathtt{integral\_constant\_tag<bool>} | |
3414 | @f] | |
3415 | ||
3416 | This clearly conveys the intention that comparing two `integral_constant`s | |
3417 | gives back another `integral_constant` holding a `bool`. In general, this | |
3418 | abstraction of the actual representation of objects makes it possible for | |
3419 | us to reason in a high level manner about functions, even though their | |
3420 | actual return and argument types are heterogeneous and not helpful. Finally, | |
3421 | most functions expect container elements to have some properties. For example, | |
3422 | this is the case of the `sort` algorithm, which obviously requires the | |
3423 | container elements to be `Orderable`. Normally, we would write the signature | |
3424 | for the non-predicated version of `sort` as | |
3425 | ||
3426 | @f[ | |
3427 | \mathtt{sort} : \mathtt{S} \to \mathtt{S} \\ | |
3428 | \text{where S is a Sequence} | |
3429 | @f] | |
3430 | ||
3431 | However, this fails to express the requirement that the contents of `S` are | |
3432 | `Orderable`. To express this, we use the following notation: | |
3433 | ||
3434 | @f[ | |
3435 | \mathtt{sort} : \mathtt{S(T)} \to \mathtt{S(T)} \\ | |
3436 | \text{where S is a Sequence and T is Orderable} | |
3437 | @f] | |
3438 | ||
3439 | One way to see this is to pretend that `S`, the sequence tag, is actually | |
3440 | parameterized by the tag of the sequence's elements, `T`. We're also pretending | |
3441 | that the elements all have the same tag `T`, which is not the case in general. | |
3442 | Now, by stating that `T` must be `Orderable`, we're expressing the fact that | |
3443 | the sequence's elements must be `Orderable`. This notation is used in different | |
3444 | flavors to express different kinds of requirements. For example, the | |
3445 | `cartesian_product` algorithm takes a sequence of sequences and returns the | |
3446 | cartesian product of those sequences as a sequence of sequences. Using our | |
3447 | notation, this can be conveyed very easily: | |
3448 | ||
3449 | @f[ | |
3450 | \mathtt{cartesian\_product} : \mathtt{S(S(T))} \to \mathtt{S(S(T))} \\ | |
3451 | \text{where S is a Sequence} | |
3452 | @f] | |
3453 | ||
3454 | ||
3455 | ||
3456 | ||
3457 | ||
3458 | ||
3459 | ||
3460 | ||
3461 | ||
3462 | ||
3463 | @section tutorial-acknowledgements Acknowledgements | |
3464 | ||
3465 | ------------------------------------------------------------------------------ | |
3466 | I'd like to thank the following persons and organizations for contributing to | |
3467 | Hana in one way or another: | |
3468 | ||
3469 | - Zach Laine and Matt Calabrese for the original idea of using function call | |
3470 | syntax to do type-level computations, as presented in their BoostCon | |
3471 | [presentation][video.inst_must_go] ([slides 1][slides.inst_must_go1]) | |
3472 | ([slides 2][slides.inst_must_go2]). | |
3473 | - Joel Falcou for mentoring me two consecutive years during my work on Hana | |
3474 | as part of the [Google Summer of Code][GSoC] program, Niall Douglas for | |
3475 | being the GSoC admin for Boost and helping me get in the program, and | |
3476 | finally Google for their awesome GSoC program. | |
3477 | - The [Boost Steering committee][Boost.Steering] for unlocking a grant for me | |
3478 | to work on Hana in the winter of 2015, as an extension to the previous | |
3479 | year's GSoC. | |
3480 | - Several [C++Now][] attendees and members of the [Boost mailing list] | |
3481 | [Boost.Devel] for insightful conversations, comments and questions | |
3482 | about the project. | |
3483 | ||
3484 | ||
3485 | ||
3486 | ||
3487 | ||
3488 | ||
3489 | ||
3490 | ||
3491 | ||
3492 | ||
3493 | @section tutorial-glossary Glossary | |
3494 | ||
3495 | ------------------------------------------------------------------------------ | |
3496 | The reference documentation uses a couple of terms that are specific to this | |
3497 | library. Also, a simplified implementation of functions is sometimes provided | |
3498 | in pseudo-code, the actual implementation sometimes being slightly hard to | |
3499 | understand. This section defines terms used in the reference and in the | |
3500 | pseudo-code used to describe some functions. | |
3501 | ||
3502 | @anchor tutorial-glossary-forwarded | |
3503 | #### `forwarded(x)` | |
3504 | Means that the object is forwarded optimally. This means that if `x` is a | |
3505 | parameter, it is `std::forward`ed, and if it is a captured variable, it is | |
3506 | moved from whenever the enclosing lambda is an rvalue. | |
3507 | ||
3508 | Also note that when `x` can be moved from, the statement `return forwarded(x);` | |
3509 | in a function with `decltype(auto)` does not mean that an rvalue reference to | |
3510 | `x` will be returned, which would create a dangling reference. Rather, it | |
3511 | means that `x` is returned by value, the value being constructed with the | |
3512 | `std::forward`ed `x`. | |
3513 | ||
3514 | @anchor tutorial-glossary-perfect_capture | |
3515 | #### `perfect-capture` | |
3516 | This is used in lambdas to signify that the captured variables are | |
3517 | initialized using perfect forwarding, as if `[x(forwarded(x))...]() { }` | |
3518 | had been used. | |
3519 | ||
3520 | @anchor tutorial-glossary-tag_dispatched | |
3521 | #### `tag-dispatched` | |
3522 | This means that the documented function uses [tag dispatching] | |
3523 | (@ref tutorial-core-tag_dispatching), and hence the exact | |
3524 | implementation depends on the model of the concept associated | |
3525 | to the function. | |
3526 | ||
3527 | @anchor tutorial-glossary-implementation_defined | |
3528 | #### `implementation-defined` | |
3529 | This expresses the fact that the exact implementation of an entity (usually a | |
3530 | type) should not be relied upon by users. In particular, this means that one | |
3531 | can not assume anything beyond what is written explicitly in the documentation. | |
3532 | Usually, the concepts satisfied by an implementation-defined entity will be | |
3533 | documented, because one could otherwise do nothing with it. Concretely, | |
3534 | assuming too much about an implementation-defined entity will probably | |
3535 | not kill you, but it will very probably break your code when you update | |
3536 | to a newer version of Hana. | |
3537 | ||
3538 | ||
3539 | ||
3540 | ||
3541 | ||
3542 | ||
3543 | ||
3544 | ||
3545 | ||
3546 | ||
3547 | @section tutorial-rationales Rationales/FAQ | |
3548 | ||
3549 | ------------------------------------------------------------------------------ | |
3550 | This section documents the rationale for some design choices. It also serves | |
3551 | as a FAQ for some (not so) frequently asked questions. If you think something | |
3552 | should be added to this list, open a GitHub issue and we'll consider either | |
3553 | improving the documentation or adding the question here. | |
3554 | ||
3555 | ||
3556 | @subsection tutorial-rationales-dependencies Why restrict usage of external dependencies? | |
3557 | ||
3558 | There are several reasons for doing so. First, Hana is a very fundamental | |
3559 | library; we are basically reimplementing the core language and the standard | |
3560 | library with support for heterogeneous types. When going through the code, | |
3561 | one quickly realizes that other libraries are rarely needed, and that almost | |
3562 | everything has to be implemented from scratch. Also, since Hana is very | |
3563 | fundamental, there is even more incentive for keeping the dependencies | |
3564 | minimal, because those dependencies will be handed down to the users. | |
3565 | Regarding the minimal reliance on Boost in particular, one big argument | |
3566 | for using it is portability. However, as a cutting edge library, Hana only | |
3567 | targets very recent compilers. Hence, we can afford to depend on modern | |
3568 | constructs and the portability given to us by using Boost would mostly | |
3569 | represent dead weight. | |
3570 | ||
3571 | ||
3572 | @subsection tutorial-rationales-iterators Why no iterators? | |
3573 | ||
3574 | Iterator based designs have their own merits, but they are also known to | |
3575 | reduce the composability of algorithms. Furthermore, the context of | |
3576 | heterogeneous programming brings a lot of points that make iterators much | |
3577 | less interesting. For example, incrementing an iterator would have to return | |
3578 | a new iterator with a different type, because the type of the new object it | |
3579 | is pointing to in the sequence might be different. It also turns out that | |
3580 | implementing most algorithms in terms of iterators leads to a worse | |
3581 | compile-time performance, simply because the execution model of metaprogramming | |
3582 | (using the compiler as an interpreter) is so different from the runtime | |
3583 | execution model of C++ (a processor accessing contiguous memory). | |
3584 | ||
3585 | ||
3586 | @subsection tutorial-rationales-container_representation Why leave some container's representation implementation-defined? | |
3587 | ||
3588 | First, it gives much more wiggle room for the implementation to perform | |
3589 | compile-time and runtime optimizations by using clever representations for | |
3590 | specific containers. For example, a tuple containing homogeneous objects of | |
3591 | type `T` could be implemented as an array of type `T` instead, which is more | |
3592 | efficient at compile-time. Secondly, and most importantly, it turns out that | |
3593 | knowing the type of a _heterogeneous_ container is not as useful as you would | |
3594 | think. Indeed, in the context of heterogeneous programming, the type of the | |
3595 | object returned by a computation is usually part of the computation too. In | |
3596 | other words, there is no way to know the type of the object returned by an | |
3597 | algorithm without actually performing the algorithm. For example, consider | |
3598 | the `find_if` algorithm: | |
3599 | ||
3600 | @snippet example/tutorial/rationale.container.cpp hana | |
3601 | ||
3602 | If the predicate is satisfied for some element of the tuple, result will be | |
3603 | equal to `just(x)`. Otherwise, `result` will be equal to `nothing`. However, | |
3604 | the `nothing`ness of the result is known at compile-time, which requires | |
3605 | `just(x)` and `nothing` to have different types. Now, say you wanted to | |
3606 | explicitly write the type of the result: | |
3607 | ||
3608 | @snippet example/tutorial/rationale.container.cpp hana-explicit | |
3609 | ||
3610 | In order to possess the knowledge of what `some_type` is, you would need to | |
3611 | actually perform the algorithm, because `some_type` depends on whether the | |
3612 | predicate is satisfied or not for some element in the container. In other | |
3613 | words, if you were able to write the above, then you would already know what | |
3614 | the result of the algorithm is and you would not need to perform the algorithm | |
3615 | in the first place. In Boost.Fusion, this problem is addressed by having a | |
3616 | separate `result_of` namespace, which contains a metafunction computing the | |
3617 | result type of any algorithm given the types of the arguments passed to it. | |
3618 | For example, the above example could be rewritten with Fusion as: | |
3619 | ||
3620 | @snippet example/tutorial/rationale.container.cpp fusion | |
3621 | ||
3622 | Notice that we're basically doing the computation twice; once in the `result_of` | |
3623 | namespace and once in the normal `fusion` namespace, which is highly redundant. | |
3624 | Before the days of `auto` and `decltype`, such techniques were necessary to | |
3625 | perform heterogeneous computations. However, since the advent of modern C++, | |
3626 | the need for explicit return types in the context of heterogeneous programming | |
3627 | is largely obsolete, and knowing the actual type of containers is usually not | |
3628 | that useful. | |
3629 | ||
3630 | ||
3631 | @subsection tutorial-rationales-why_Hana Why Hana? | |
3632 | ||
3633 | No, it isn't the name of my girlfriend! I just needed a short and good looking | |
3634 | name that people would easily remember, and Hana came up. It also came to my | |
3635 | attention that Hana means _flower_ in Japanese, and _one_ in Korean. Since | |
3636 | Hana is pretty and it unifies type-level and heterogeneous programming under | |
3637 | a single paradigm, the name appears to be quite well chosen in retrospect :-). | |
3638 | ||
3639 | ||
3640 | @subsection tutorial-rationales-tuple Why define our own tuple? | |
3641 | ||
3642 | Since Hana defines a lot of algorithms on tuples, a possible way to go would | |
3643 | have been to simply use `std::tuple` and provide the algorithms only, instead | |
3644 | of also providing our own tuple. The reason for providing our own tuple is | |
3645 | principally performance. Indeed, all the `std::tuple` implementations tested | |
3646 | so far have a very bad compile-time performance. Also, to get truly amazing | |
3647 | compile-time performance, we need to take advantage of the tuple's internal | |
3648 | representation in some algorithms, which requires defining our own. Finally, | |
3649 | some sugar like `operator[]` could not be provided if we were using a | |
3650 | `std::tuple`, since that operator must be defined as a member function. | |
3651 | ||
3652 | ||
3653 | @subsection tutorial-rationales-naming How are names chosen? | |
3654 | ||
3655 | When deciding upon a name `X`, I try to balance the following things | |
3656 | (in no specific order): | |
3657 | ||
3658 | - How idiomatic is `X` in C++? | |
3659 | - How idiomatic is `X` in the rest of the programming world? | |
3660 | - How good of a name `X` _actually is_, regardless of historical reasons | |
3661 | - How do I, as the library author, feel about `X` | |
3662 | - How do users of the library feel about `X` | |
3663 | - Are there technical reasons not to use `X`, like name clashes or names | |
3664 | reserved by the standard | |
3665 | ||
3666 | Of course, good naming is and will always be hard. Names are and will always | |
3667 | be tainted by the author's own bias. Still, I try to choose names in a | |
3668 | reasonable manner. | |
3669 | ||
3670 | ||
3671 | @subsection tutorial-rationales-parameters How is the parameter order decided? | |
3672 | ||
3673 | Unlike naming, which is fairly subjective, the order of the parameters of a | |
3674 | function is usually pretty straightforward to determine. Basically, the rule | |
3675 | of thumb is "the container goes first". It has always been this way in Fusion | |
3676 | and MPL, and this is intuitive for most C++ programmers. Also, in higher-order | |
3677 | algorithms, I try to put the function parameter last, so that multi-line | |
3678 | lambdas look nice: | |
3679 | ||
3680 | @code{cpp} | |
3681 | algorithm(container, [](auto x) { | |
3682 | return ...; | |
3683 | }); | |
3684 | ||
3685 | // is nicer than | |
3686 | ||
3687 | algorithm([](auto x) { | |
3688 | return ...; | |
3689 | }, container); | |
3690 | @endcode | |
3691 | ||
3692 | ||
3693 | @subsection tutorial-rationales-tag_dispatching Why tag dispatching? | |
3694 | ||
3695 | There are several different techniques we could have used to provide | |
3696 | customization points in the library, and tag-dispatching was chosen. Why? | |
3697 | First, I wanted a two-layer dispatching system because this allows functions | |
3698 | from the first layer (the ones that are called by users) to actually be | |
3699 | function objects, which allows passing them to higher-order algorithms. | |
3700 | Using a dispatching system with two layers also allows adding some | |
3701 | compile-time sanity checks to the first layer, which improves error messages. | |
3702 | ||
3703 | Now, tag-dispatching was chosen over other techniques with two layers for a | |
3704 | couple of reasons. First, having to explicitly state how some tag is a model | |
3705 | of a concept gives the responsibility of making sure that the semantic | |
3706 | requirements of the concept are respected to the user. Secondly, when checking | |
3707 | whether a type is a model of some concept, we basically check that some key | |
3708 | functions are implemented. In particular, we check that the functions from the | |
3709 | minimal complete definition of that concept are implemented. For example, | |
3710 | `Iterable<T>` checks whether the `is_empty`, `at` and `drop_front` functions | |
3711 | implemented for `T`. However, the only way to detect this without | |
3712 | tag-dispatching is to basically check whether the following expressions | |
3713 | are valid in a SFINAE-able context: | |
3714 | ||
3715 | @code{cpp} | |
3716 | implementation_of_at(std::declval<T>(), std::declval<N>()) | |
3717 | implementation_of_is_empty(std::declval<T>()) | |
3718 | implementation_of_drop_front(std::declval<T>()) | |
3719 | @endcode | |
3720 | ||
3721 | Unfortunately, this requires actually doing the algorithms, which might either | |
3722 | trigger a hard compile-time error or hurt compile-time performance. Also, this | |
3723 | requires picking an arbitrary index `N` to call `at` with: what if the `Iterable` | |
3724 | is empty? With tag dispatching, we can just ask whether `at_impl<T>`, | |
3725 | `is_empty_impl<T>` and `drop_front_impl<T>` are defined, and nothing happens | |
3726 | until we actually call their nested `::%apply` function. | |
3727 | ||
3728 | ||
3729 | @subsection tutorial-rationales-zip_longest Why not provide zip_longest? | |
3730 | ||
3731 | It would require either (1) padding the shortest sequences with an arbitrary | |
3732 | object, or (2) padding the shortest sequences with an object provided by the | |
3733 | user when calling `zip_longest`. Since there is no requirement that all the | |
3734 | zipped sequences have elements of similar types, there is no way to provide a | |
3735 | single consistent padding object in all cases. A tuple of padding objects | |
3736 | should be provided, but I find it perhaps too complicated to be worth it for | |
3737 | now. If you need this functionality, open a GitHub issue. | |
3738 | ||
3739 | ||
3740 | @subsection tutorial-rationales-concepts Why aren't concepts constexpr functions? | |
3741 | ||
3742 | Since the C++ concept proposal maps concepts to boolean `constexpr` functions, | |
3743 | it would make sense that Hana defines its concepts as such too, instead of as | |
3744 | structs with a nested `::%value`. Indeed, this was the first choice, but it | |
3745 | had to be revised because template functions have one limitation that makes | |
3746 | them less flexible. Specifically, a template function can't be passed to a | |
3747 | higher-order metafunction. In other words, it is not possible to write the | |
3748 | following | |
3749 | ||
3750 | @code{cpp} | |
3751 | template <??? Concept> | |
3752 | struct some_metafunction { | |
3753 | // ... | |
3754 | }; | |
3755 | @endcode | |
3756 | ||
3757 | This sort of code is very useful in some contexts, such as checking whether | |
3758 | two types have a common embedding modeling a concept: | |
3759 | ||
3760 | @code{cpp} | |
3761 | template <??? Concept, typename T, typename U> | |
3762 | struct have_common_embedding { | |
3763 | // whether T and U both model Concept, and share a common type that also models Concept | |
3764 | }; | |
3765 | @endcode | |
3766 | ||
3767 | With concepts as boolean `constexpr` functions, this can't be written | |
3768 | generically. When concepts are just template structs, however, we can | |
3769 | use template template parameters: | |
3770 | ||
3771 | @code{cpp} | |
3772 | template <template <typename ...> class Concept, typename T, typename U> | |
3773 | struct have_common_embedding { | |
3774 | // whether T and U both model Concept, and share a common type that also models Concept | |
3775 | }; | |
3776 | @endcode | |
3777 | ||
3778 | ||
3779 | ||
3780 | ||
3781 | ||
3782 | ||
3783 | ||
3784 | ||
3785 | ||
3786 | ||
3787 | @section tutorial-appendix-constexpr Appendix I: Advanced constexpr | |
3788 | ||
3789 | ------------------------------------------------------------------------------ | |
3790 | In C++, the border between compile-time and runtime is hazy, a fact that is | |
3791 | even more true with the introduction of [generalized constant expressions] | |
3792 | [C++14.gconstexpr] in C++14. However, being able to manipulate heterogeneous | |
3793 | objects is all about understanding that border and then crossing it at one's | |
3794 | will. The goal of this section is to set things straight with `constexpr`; to | |
3795 | understand which problems it can solve and which ones it can't. This section | |
3796 | covers advanced concepts about to constant expressions; only readers with a | |
3797 | good understanding of `constexpr` should attempt to read this. | |
3798 | ||
3799 | ||
3800 | @subsection tutorial-appendix-constexpr-stripping Constexpr stripping | |
3801 | ||
3802 | Let's start with a challenging question. Should the following code compile? | |
3803 | ||
3804 | @code{cpp} | |
3805 | template <typename T> | |
3806 | void f(T t) { | |
3807 | static_assert(t == 1, ""); | |
3808 | } | |
3809 | ||
3810 | constexpr int one = 1; | |
3811 | f(one); | |
3812 | @endcode | |
3813 | ||
3814 | The answer is no, and the error given by Clang goes like | |
3815 | ||
3816 | @code{cpp} | |
3817 | error: static_assert expression is not an integral constant expression | |
3818 | static_assert(t == 1, ""); | |
3819 | ^~~~~~ | |
3820 | @endcode | |
3821 | ||
3822 | The explanation is that inside of `f`'s body, `t` is not a constant expression, | |
3823 | and hence it can't be used as the operand to a `static_assert`. The reason is | |
3824 | that such a function simply can't be generated by the compiler. To understand | |
3825 | the issue, consider what should happen when we instantiate the `f` template | |
3826 | with a concrete type: | |
3827 | ||
3828 | @code{cpp} | |
3829 | // Here, the compiler should generate the code for f<int> and store the | |
3830 | // address of that code into fptr. | |
3831 | void (*fptr)(int) = f<int>; | |
3832 | @endcode | |
3833 | ||
3834 | Clearly, the compiler can't generate `f<int>`'s code, which should trigger a | |
3835 | `static_assert` if `t != 1`, because we haven't specified `t` yet. Even worse, | |
3836 | the generated function should work on both constant and non-constant | |
3837 | expressions: | |
3838 | ||
3839 | @code{cpp} | |
3840 | void (*fptr)(int) = f<int>; // assume this was possible | |
3841 | int i = ...; // user input | |
3842 | fptr(i); | |
3843 | @endcode | |
3844 | ||
3845 | Clearly, `fptr`'s code can't be generated, because it would require being able | |
3846 | to `static_assert` on a runtime value, which does not make sense. Furthermore, | |
3847 | note that it does not matter whether you make the function `constexpr` or not; | |
3848 | making `f` `constexpr` would only state that the _result_ of `f` is a constant | |
3849 | expression whenever its argument is a constant expression, but it still does | |
3850 | not give you the ability to know whether you were called with a constant | |
3851 | expression from `f`'s body. In other words, what we would want is something | |
3852 | like: | |
3853 | ||
3854 | @code{cpp} | |
3855 | template <typename T> | |
3856 | void f(constexpr T t) { | |
3857 | static_assert(t == 1, ""); | |
3858 | } | |
3859 | ||
3860 | constexpr int one = 1; | |
3861 | f(one); | |
3862 | @endcode | |
3863 | ||
3864 | In this hypothetical scenario, the compiler would know that `t` is a constant | |
3865 | expression from the body of `f`, and the `static_assert` could be made to work. | |
3866 | However, `constexpr` parameters do not exist in the current language, and | |
3867 | adding them would bring up very challenging design and implementation issues. | |
3868 | The conclusion of this little experiment is that __argument passing strips | |
3869 | away `constexpr`-ness__. What might be unclear by now are the consequences | |
3870 | of this stripping, which are explained next. | |
3871 | ||
3872 | ||
3873 | @subsection tutorial-tutorial-appendix-constexpr-preservation Constexpr preservation | |
3874 | ||
3875 | The fact that an argument is not a constant expression means that we can't use | |
3876 | it as a non-type template parameter, as an array bound, inside a `static_assert` | |
3877 | or anything else that requires a constant expression. In addition, this means | |
3878 | that the return type of a function can't depend on the _value_ of an argument | |
3879 | which is nothing new if you think about it: | |
3880 | ||
3881 | @code{cpp} | |
3882 | template <int i> | |
3883 | struct foo { }; | |
3884 | ||
3885 | auto f(int i) -> foo<i>; // obviously won't work | |
3886 | @endcode | |
3887 | ||
3888 | In fact, the return type of a function may only depend on the types of its | |
3889 | arguments, and `constexpr` can't change this fact. This is of utmost importance | |
3890 | to us, because we're interested in manipulating heterogeneous objects, which | |
3891 | eventually means returning objects with different types depending on the | |
3892 | argument of the function. For example, a function might want to return an | |
3893 | object of type `T` in one case and an object of type `U` in the other; | |
3894 | from our analysis, we now know that these "cases" will have to depend on | |
3895 | information encoded in the _types_ of the arguments, not in their _values_. | |
3896 | ||
3897 | To preserve `constexpr`-ness through argument passing, we have to encode the | |
3898 | `constexpr` value into a type, and then pass a not-necessarily-`constexpr` | |
3899 | object of that type to the function. The function, which must be a template, | |
3900 | may then access the `constexpr` value encoded inside that type. | |
3901 | ||
3902 | @todo | |
3903 | Improve this explanation and talk about non-integral constant expressions | |
3904 | wrapped into types. | |
3905 | ||
3906 | ||
3907 | @subsection tutorial-appendix-constexpr-effects Side effects | |
3908 | ||
3909 | Let me ask a tricky question. Is the following code valid? | |
3910 | ||
3911 | @code{cpp} | |
3912 | template <typename T> | |
3913 | constexpr int f(T& n) { return 1; } | |
3914 | ||
3915 | int n = 0; | |
3916 | constexpr int i = f(n); | |
3917 | @endcode | |
3918 | ||
3919 | The answer is _yes_, but the reason might not be obvious at first. What | |
3920 | happens here is that we have a non-`constexpr` `int n`, and a `constexpr` | |
3921 | function `f` taking a reference to its argument. The reason why most people | |
3922 | think it shouldn't work is that `n` is not `constexpr`. However, we're not | |
3923 | doing anything with `n` inside of `f`, so there is no actual reason why this | |
3924 | shouldn't work! This is a bit like `throw`ing inside of a `constexpr` function: | |
3925 | ||
3926 | @code{cpp} | |
3927 | constexpr int sqrt(int i) { | |
3928 | if (i < 0) throw "i should be non-negative"; | |
3929 | ||
3930 | return ...; | |
3931 | } | |
3932 | ||
3933 | constexpr int two = sqrt(4); // ok: did not attempt to throw | |
3934 | constexpr int error = sqrt(-4); // error: can't throw in a constant expression | |
3935 | @endcode | |
3936 | ||
3937 | As long as the code path where `throw` appears is not executed, the result of | |
3938 | the invocation can be a constant expression. Similarly, we can do whatever we | |
3939 | want inside of `f`, as long as we don't execute a code path that requires | |
3940 | accessing its argument `n`, which is not a constant expression: | |
3941 | ||
3942 | @code{cpp} | |
3943 | template <typename T> | |
3944 | constexpr int f(T& n, bool touch_n) { | |
3945 | if (touch_n) n + 1; | |
3946 | return 1; | |
3947 | } | |
3948 | ||
3949 | int n = 0; | |
3950 | constexpr int i = f(n, false); // ok | |
3951 | constexpr int j = f(n, true); // error | |
3952 | @endcode | |
3953 | ||
3954 | The error given by Clang for the second invocation is | |
3955 | ||
3956 | @code{cpp} | |
3957 | error: constexpr variable 'j' must be initialized by a constant expression | |
3958 | constexpr int j = f(n, true); // error | |
3959 | ^ ~~~~~~~~~~ | |
3960 | note: read of non-const variable 'n' is not allowed in a constant expression | |
3961 | if (touch_n) n + 1; | |
3962 | ^ | |
3963 | @endcode | |
3964 | ||
3965 | Let's now step the game up a bit and consider a more subtle example. | |
3966 | Is the following code valid? | |
3967 | ||
3968 | @code{cpp} | |
3969 | template <typename T> | |
3970 | constexpr int f(T n) { return 1; } | |
3971 | ||
3972 | int n = 0; | |
3973 | constexpr int i = f(n); | |
3974 | @endcode | |
3975 | ||
3976 | The only difference with our initial scenario is that `f` now takes its | |
3977 | argument by value instead of by reference. However, this makes a world of | |
3978 | difference. Indeed, we're now asking the compiler to make a copy of `n` | |
3979 | and to pass this copy to `f`. However, `n` is not `constexpr`, so its | |
3980 | value is only known at runtime. How could the compiler make a copy (at | |
3981 | compile-time) of a variable whose value is only known at runtime? Of | |
3982 | course, it can't. Indeed, the error message given by Clang is pretty | |
3983 | explicit about what's happening: | |
3984 | ||
3985 | @code{cpp} | |
3986 | error: constexpr variable 'i' must be initialized by a constant expression | |
3987 | constexpr int i = f(n); | |
3988 | ^ ~~~~ | |
3989 | note: read of non-const variable 'n' is not allowed in a constant expression | |
3990 | constexpr int i = f(n); | |
3991 | ^ | |
3992 | @endcode | |
3993 | ||
3994 | @todo | |
3995 | Explain how side-effects may not appear inside constant expressions, even | |
3996 | if the expression they yield are not accessed. | |
3997 | ||
3998 | <!------------------- | |
3999 | Let me ask a tricky question. Is the following code valid? | |
4000 | ||
4001 | @code{cpp} | |
4002 | template <typename X> | |
4003 | auto identity(X x) { return x; } | |
4004 | ||
4005 | static_assert(value(identity(bool_c<true>)), ""); | |
4006 | @endcode | |
4007 | ||
4008 | The answer is "no", but the reason might not be obvious at first. Even more | |
4009 | puzzling is that the following code is perfectly valid: | |
4010 | ||
4011 | @snippet example/tutorial/constant_side_effects.cpp pure | |
4012 | ||
4013 | To understand why the compiler can't possibly evaluate the first assertion | |
4014 | at compile-time, notice that `identity` was not marked `constexpr` and | |
4015 | consider the following alternative (but valid) definition for `identity`: | |
4016 | ||
4017 | @snippet example/tutorial/constant_side_effects.cpp impure_identity | |
4018 | ||
4019 | The signature of the function did not change; the function could even have | |
4020 | been defined in a separate source file. However, it is now obvious that the | |
4021 | compiler can't evaluate that expression at compile-time. On the other hand, | |
4022 | when we write | |
4023 | ||
4024 | @snippet example/tutorial/constant_side_effects.cpp impure | |
4025 | ||
4026 | we're telling the compiler to perform those potential side effects during the | |
4027 | dynamic initialization phase! Then, we use `value` to return the compile-time | |
4028 | value associated to its argument. Also note that `value` takes a `const&` to | |
4029 | its argument; if it tried taking it by value, we would be reading from a | |
4030 | non-`constexpr` variable to do the copying, and that could hide side-effects. | |
4031 | ------> | |
4032 | ||
4033 | ||
4034 | ||
4035 | ||
4036 | ||
4037 | ||
4038 | ||
4039 | ||
4040 | ||
4041 | ||
4042 | @section tutorial-appendix-MPL Appendix II: A minimal MPL | |
4043 | ||
4044 | ------------------------------------------------------------------------------ | |
4045 | This section presents a mini reimplementation of the MPL library. The goal is | |
4046 | to be as backward compatible as possible with the MPL, while still using Hana | |
4047 | under the hood. Only the "Algorithms" part of the MPL is implemented as a case | |
4048 | study, but it should be possible to implement many (but not all) metafunctions | |
4049 | of the MPL. | |
4050 | ||
4051 | Scroll down to the `main` function to see the tests. The tests are exactly | |
4052 | the examples in the MPL documentation that were copy/pasted and then | |
4053 | modified as little as possible to work with this reimplementation. | |
4054 | ||
4055 | @include example/tutorial/appendix_mpl.cpp | |
4056 | ||
4057 | ||
4058 | ||
4059 | ||
4060 | ||
4061 | ||
4062 | ||
4063 | ||
4064 | ||
4065 | ||
4066 | <!-- Links --> | |
4067 | [Boost.Devel]: http://news.gmane.org/gmane.comp.lib.boost.devel | |
4068 | [Boost.Fusion]: http://www.boost.org/doc/libs/release/libs/fusion/doc/html/index.html | |
4069 | [Boost.MPL]: http://www.boost.org/doc/libs/release/libs/mpl/doc/index.html | |
4070 | [Boost.Steering]: https://sites.google.com/a/boost.org/steering/home | |
4071 | [Brigand]: https://github.com/edouarda/brigand | |
4072 | [C++14.auto_rt]: http://en.wikipedia.org/wiki/C%2B%2B14#Function_return_type_deduction | |
4073 | [C++14.gconstexpr]: http://en.wikipedia.org/wiki/C%2B%2B11#constexpr_.E2.80.93_Generalized_constant_expressions | |
4074 | [C++14.glambda]: http://en.wikipedia.org/wiki/C%2B%2B14#Generic_lambdas | |
4075 | [C++14.ice]: http://en.cppreference.com/w/cpp/types/integral_constant | |
4076 | [C++14.udl]: http://en.wikipedia.org/wiki/C%2B%2B11#User-defined_literals | |
4077 | [C++14.vtemplate]: http://en.wikipedia.org/wiki/C%2B%2B14#Variable_templates | |
4078 | [C++14]: http://en.wikipedia.org/wiki/C%2B%2B14 | |
4079 | [C++17.clite]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3580.pdf | |
4080 | [C++Now]: http://cppnow.org | |
4081 | [Chandler.MeetingC++]: https://youtu.be/qkzaZumt_uk?t=4478 | |
4082 | [CMake]: http://www.cmake.org | |
4083 | [constexpr_throw]: http://stackoverflow.com/a/8626450/627587 | |
4084 | [CopyConstructible]: http://en.cppreference.com/w/cpp/concept/CopyConstructible | |
4085 | [GOTW]: http://www.gotw.ca/gotw/index.htm | |
4086 | [GSoC]: http://www.google-melange.com/gsoc/homepage/google/gsoc2014 | |
4087 | [Hana.chat]: https://gitter.im/boostorg/hana | |
4088 | [Hana.contributing]: https://github.com/boostorg/hana/blob/master/CONTRIBUTING.md#how-to-contribute | |
4089 | [Hana.findmodule]: https://github.com/boostorg/hana/blob/master/cmake/FindHana.cmake | |
4090 | [Hana.hacking]: https://github.com/boostorg/hana/blob/master/README.md#hacking-on-hana | |
4091 | [Hana.issues]: https://github.com/boostorg/hana/issues | |
4092 | [Hana.repository]: https://github.com/boostorg/hana | |
4093 | [Hana.StackOverflow]: http://stackoverflow.com/questions/tagged/boost-hana | |
4094 | [Hana.wiki]: https://github.com/boostorg/hana/wiki | |
4095 | [Homebrew]: http://brew.sh | |
4096 | [lie-to-children]: http://en.wikipedia.org/wiki/Lie-to-children | |
4097 | [Metabench]: https://ldionne.github.io/metabench | |
4098 | [MPL.arithmetic]: http://www.boost.org/doc/libs/release/libs/mpl/doc/refmanual/arithmetic-operations.html | |
4099 | [MPL.metafunction]: http://www.boost.org/doc/libs/release/libs/mpl/doc/refmanual/metafunction.html | |
4100 | [MPL.mfc]: http://www.boost.org/doc/libs/release/libs/mpl/doc/refmanual/metafunction-class.html | |
4101 | [MPL11]: http://github.com/ldionne/mpl11 | |
4102 | [N4461]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4461.html | |
4103 | [N4487]: https://isocpp.org/files/papers/N4487.pdf | |
4104 | [pkg-config]: http://www.freedesktop.org/wiki/Software/pkg-config/ | |
4105 | [POD]: http://en.cppreference.com/w/cpp/concept/PODType | |
4106 | [SFINAE]: http://en.cppreference.com/w/cpp/language/sfinae | |
4107 | [slides.inst_must_go1]: https://github.com/boostcon/2010_presentations/raw/master/mon/instantiations_must_go.pdf | |
4108 | [slides.inst_must_go2]: https://github.com/boostcon/2010_presentations/raw/master/mon/instantiations_must_go_2.pdf | |
4109 | [SO.sfinae]: http://stackoverflow.com/a/257382/627587 | |
4110 | [Sprout]: https://github.com/bolero-MURAKAMI/Sprout | |
4111 | [StackOverflow]: http://stackoverflow.com | |
4112 | [video.inst_must_go]: https://www.youtube.com/watch?v=x7UmrRzKAXU | |
4113 | ||
4114 | */ |