| 1 | /*! |
| 2 | @file |
| 3 | Forward declares `boost::hana::Struct`. |
| 4 | |
| 5 | Copyright Louis Dionne 2013-2022 |
| 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 | namespace boost { namespace hana { |
| 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 | }} // end namespace boost::hana |
| 155 | |
| 156 | #endif // !BOOST_HANA_FWD_CONCEPT_STRUCT_HPP |
| 157 | |