1 /*! 2 @file 3 Forward declares `boost::hana::Struct`. 4 5 @copyright Louis Dionne 2013-2017 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