]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*! |
2 | @file | |
3 | Forward declares `boost::hana::Struct`. | |
4 | ||
5 | @copyright Louis Dionne 2013-2016 | |
6 | Distributed under the Boost Software License, Version 1.0. | |
7 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) | |
8 | */ | |
9 | ||
10 | #ifndef BOOST_HANA_FWD_CONCEPT_STRUCT_HPP | |
11 | #define BOOST_HANA_FWD_CONCEPT_STRUCT_HPP | |
12 | ||
13 | #include <boost/hana/config.hpp> | |
14 | ||
15 | ||
16 | BOOST_HANA_NAMESPACE_BEGIN | |
17 | //! @ingroup group-concepts | |
18 | //! @defgroup group-Struct Struct | |
19 | //! The `Struct` concept represents `struct`-like user-defined types. | |
20 | //! | |
21 | //! The `Struct` concept allows restricted compile-time reflection over | |
22 | //! user-defined types. In particular, it allows accessing the names of | |
23 | //! the members of a user-defined type, and also the value of those | |
24 | //! members. `Struct`s can also be folded, searched and converted to | |
25 | //! some types of containers, where more advanced transformations can | |
26 | //! be performed. | |
27 | //! | |
28 | //! While all types can _in theory_ be made `Struct`s, only a subset of | |
29 | //! them are actually interesting to see as such. More precisely, it is | |
30 | //! only interesting to make a type a `Struct` when it is conceptually | |
31 | //! a C++ `struct`, i.e. a mostly dumb aggregate of named data. The way | |
32 | //! this data is accessed is mostly unimportant to the `Struct` concept; | |
33 | //! it could be through getters and setters, through public members, | |
34 | //! through non-member functions or it could even be generated on-the-fly. | |
35 | //! The important part, which is made precise below, is that those accessor | |
36 | //! methods should be move-independent. | |
37 | //! | |
38 | //! Another way to see a `Struct` is as a map where the keys are the names | |
39 | //! of the members and the values are the values of those members. However, | |
40 | //! there are subtle differences like the fact that one can't add a member | |
41 | //! to a `Struct`, and also that the order of the members inside a `Struct` | |
42 | //! plays a role in determining the equality of `Struct`s, which is not | |
43 | //! the case for maps. | |
44 | //! | |
45 | //! | |
46 | //! Minimal complete definition | |
47 | //! --------------------------- | |
48 | //! `accessors` | |
49 | //! | |
50 | //! A model of `Struct` is created by specifying a sequence of key/value | |
51 | //! pairs with the `accessors` function. The first element of a pair in | |
52 | //! this sequence represents the "name" of a member of the `Struct`, while | |
53 | //! the second element is a function which retrieves this member from an | |
54 | //! object. The "names" do not have to be in any special form; they just | |
55 | //! have to be compile-time `Comparable`. For example, it is common to | |
56 | //! provide "names" that are `hana::string`s representing the actual names | |
57 | //! of the members, but one could provide `hana::integral_constant`s just | |
58 | //! as well. The values must be functions which, when given an object, | |
59 | //! retrieve the appropriate member from it. | |
60 | //! | |
61 | //! There are several ways of providing the `accessors` method, some of | |
62 | //! which are more flexible and others which are more convenient. First, | |
63 | //! one can define it through tag-dispatching, as usual. | |
64 | //! @snippet example/struct.mcd.tag_dispatching.cpp main | |
65 | //! | |
66 | //! Secondly, it is possible to provide a nested `hana_accessors_impl` | |
67 | //! type, which should be equivalent to a specialization of | |
68 | //! `accessors_impl` for tag-dispatching. However, for a type `S`, this | |
69 | //! technique only works when the data type of `S` is `S` itself, which | |
70 | //! is the case unless you explicitly asked for something else. | |
71 | //! @snippet example/struct.mcd.nested.cpp main | |
72 | //! | |
73 | //! Finally, the most convenient (but least flexible) option is to use | |
74 | //! the `BOOST_HANA_DEFINE_STRUCT`, the `BOOST_HANA_ADAPT_STRUCT` or the | |
75 | //! `BOOST_HANA_ADAPT_ADT` macro, which provide a minimal syntactic | |
76 | //! overhead. See the documentation of these macros for details on how | |
77 | //! to use them. | |
78 | //! | |
79 | //! Also note that it is not important that the accessor functions retrieve | |
80 | //! an actual member of the struct (e.g. `x.member`). Indeed, an accessor | |
81 | //! function could call a custom getter or even compute the value of the | |
82 | //! member on the fly: | |
83 | //! @snippet example/struct.custom_accessor.cpp main | |
84 | //! | |
85 | //! The only important thing is that the accessor functions are | |
86 | //! move-independent, a notion which is defined below. | |
87 | //! | |
88 | //! | |
89 | //! @anchor move-independence | |
90 | //! Move-independence | |
91 | //! ----------------- | |
92 | //! The notion of move-independence presented here defines rigorously | |
93 | //! when it is legitimate to "double-move" from an object. | |
94 | //! | |
95 | //! A collection of functions `f1, ..., fn` sharing the same domain is | |
96 | //! said to be _move-independent_ if for every fresh (not moved-from) | |
97 | //! object `x` in the domain, any permutation of the following statements | |
98 | //! is valid and leaves the `zk` objects in a fresh (not moved-from) state: | |
99 | //! @code | |
100 | //! auto z1 = f1(std::move(x)); | |
101 | //! ... | |
102 | //! auto zn = fn(std::move(x)); | |
103 | //! @endcode | |
104 | //! | |
105 | //! @note | |
106 | //! In the special case where some functions return objects that can't be | |
107 | //! bound to with `auto zk =` (like `void` or a non-movable, non-copyable | |
108 | //! type), just pretend the return value is ignored. | |
109 | //! | |
110 | //! Intuitively, this ensures that we can treat `f1, ..., fn` as | |
111 | //! "accessors" that decompose `x` into independent subobjects, and | |
112 | //! that do so without moving from `x` more than that subobject. This | |
113 | //! is important because it allows us to optimally decompose `Struct`s | |
114 | //! into their subparts inside the library. | |
115 | //! | |
116 | //! | |
117 | //! Laws | |
118 | //! ---- | |
119 | //! For any `Struct` `S`, the accessors in the `accessors<S>()` sequence | |
120 | //! must be move-independent, as defined above. | |
121 | //! | |
122 | //! | |
123 | //! Refined concepts | |
124 | //! ---------------- | |
125 | //! 1. `Comparable` (free model)\n | |
126 | //! `Struct`s are required to be `Comparable`. Specifically, two `Struct`s | |
127 | //! of the same data type `S` must be equal if and only if all of their | |
128 | //! members are equal. By default, a model of `Comparable` doing just that | |
129 | //! is provided for models of `Struct`. In particular, note that the | |
130 | //! comparison of the members is made in the same order as they appear in | |
131 | //! the `hana::members` sequence. | |
132 | //! @include example/struct/comparable.cpp | |
133 | //! | |
134 | //! 2. `Foldable` (free model)\n | |
135 | //! A `Struct` can be folded by considering it as a list of pairs each | |
136 | //! containing the name of a member and the value associated to that | |
137 | //! member, in the same order as they appear in the `hana::members` | |
138 | //! sequence. By default, a model of `Foldable` doing just that is | |
139 | //! provided for models of the `Struct` concept. | |
140 | //! @include example/struct/foldable.cpp | |
141 | //! Being a model of `Foldable` makes it possible to turn a `Struct` | |
142 | //! into basically any `Sequence`, but also into a `hana::map` by simply | |
143 | //! using the `to<...>` function! | |
144 | //! @include example/struct/to.cpp | |
145 | //! | |
146 | //! 3. `Searchable` (free model)\n | |
147 | //! A `Struct` can be searched by considering it as a map where the keys | |
148 | //! are the names of the members of the `Struct`, and the values are the | |
149 | //! members associated to those names. By default, a model of `Searchable` | |
150 | //! is provided for any model of the `Struct` concept. | |
151 | //! @include example/struct/searchable.cpp | |
152 | template <typename S> | |
153 | struct Struct; | |
154 | BOOST_HANA_NAMESPACE_END | |
155 | ||
156 | #endif // !BOOST_HANA_FWD_CONCEPT_STRUCT_HPP |