]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [/============================================================================== |
2 | Copyright (C) 2001-2011 Joel de Guzman | |
3 | Copyright (C) 2006 Dan Marsden | |
4 | Copyright (C) 2010 Christopher Schmidt | |
5 | ||
6 | Use, modification and distribution is subject to the Boost Software | |
7 | License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
8 | http://www.boost.org/LICENSE_1_0.txt) | |
9 | ===============================================================================/] | |
10 | [section Notes] | |
11 | ||
12 | [heading Recursive Inlined Functions] | |
13 | ||
14 | An interesting peculiarity of functions like __at__ when applied to a | |
15 | __forward_sequence__ like __list__ is that what could have been linear | |
16 | runtime complexity effectively becomes constant O(1) due to compiler | |
17 | optimization of C++ inlined functions, however deeply recursive (up to a | |
18 | certain compiler limit of course). Compile time complexity remains linear. | |
19 | ||
20 | [heading Overloaded Functions] | |
21 | ||
22 | Associative sequences use function overloading to implement membership | |
23 | testing and type associated key lookup. This amounts to constant runtime | |
24 | and amortized constant compile time complexities. There is an overloaded | |
25 | function, `f(k)`, for each key /type/ `k`. The compiler chooses the | |
26 | appropriate function given a key, `k`. | |
27 | ||
28 | [heading Tag Dispatching] | |
29 | ||
30 | Tag dispatching is a generic programming technique for selecting template | |
31 | specializations. There are typically 3 components involved in the tag | |
32 | dispatching mechanism: | |
33 | ||
34 | # A type for which an appropriate template specialization is required | |
35 | # A metafunction that associates the type with a tag type | |
36 | # A template that is specialized for the tag type | |
37 | ||
38 | For example, the fusion `result_of::begin` metafunction is implemented | |
39 | as follows: | |
40 | ||
41 | template <typename Sequence> | |
42 | struct begin | |
43 | { | |
44 | typedef typename | |
45 | result_of::begin_impl<typename traits::tag_of<Sequence>::type>:: | |
46 | template apply<Sequence>::type | |
47 | type; | |
48 | }; | |
49 | ||
50 | In the case: | |
51 | ||
52 | # `Sequence` is the type for which a suitable implementation of | |
53 | `result_of::begin_impl` is required | |
54 | # `traits::tag_of` is the metafunction that associates `Sequence` | |
55 | with an appropriate tag | |
56 | # `result_of::begin_impl` is the template which is specialized to provide | |
57 | an implementation for each tag type | |
58 | ||
59 | [heading Extensibility] | |
60 | ||
61 | Unlike __mpl__, there is no extensible sequence concept in fusion. This does | |
62 | not mean that Fusion sequences are not extensible. In fact, all Fusion | |
63 | sequences are inherently extensible. It is just that the manner of sequence | |
64 | extension in Fusion is different from both __stl__ and __mpl__ on account of | |
65 | the lazy nature of fusion __algorithms__. __stl__ containers extend | |
66 | themselves in place though member functions such as __push_back__ and | |
67 | __insert__. __mpl__ sequences, on the other hand, are extended through | |
68 | "intrinsic" functions that actually return whole sequences. __mpl__ is | |
69 | purely functional and can not have side effects. For example, __mpl__'s | |
70 | `push_back` does not actually mutate an `mpl::vector`. It can't do that. | |
71 | Instead, it returns an extended `mpl::vector`. | |
72 | ||
73 | Like __mpl__, Fusion too is purely functional and can not have side | |
74 | effects. With runtime efficiency in mind, Fusion sequences are extended | |
75 | through generic functions that return __views__. __views__ are sequences | |
76 | that do not actually contain data, but instead impart an alternative | |
77 | presentation over the data from one or more underlying sequences. __views__ | |
78 | are proxies. They provide an efficient yet purely functional way to work on | |
79 | potentially expensive sequence operations. For example, given a __vector__, | |
80 | Fusion's __push_back__ returns a __joint_view__, instead of an actual | |
81 | extended __vector__. A __joint_view__ holds a reference to the original | |
82 | sequence plus the appended data --making it very cheap to pass around. | |
83 | ||
84 | [heading Element Conversion] | |
85 | ||
86 | Functions that take in elemental values to form sequences (e.g. | |
87 | __make_list__) convert their arguments to something suitable to be stored | |
88 | as a sequence element. In general, the element types are stored as plain | |
89 | values. Example: | |
90 | ||
91 | __make_list__(1, 'x') | |
92 | ||
93 | returns a __list__`<int, char>`. | |
94 | ||
95 | There are a few exceptions, however. | |
96 | ||
97 | [*Arrays:] | |
98 | ||
99 | Array arguments are deduced to reference to const types. For example | |
100 | [footnote Note that the type of a string literal is an array of const | |
101 | characters, not `const char*`. To get __make_list__ to create a __list__ | |
102 | with an element of a non-const array type one must use the `ref` wrapper | |
103 | (see __note_ref_wrappers__).]: | |
104 | ||
105 | __make_list__("Donald", "Daisy") | |
106 | ||
107 | creates a __list__ of type | |
108 | ||
109 | __list__<const char (&)[7], const char (&)[6]> | |
110 | ||
111 | [*Function pointers:] | |
112 | ||
113 | Function pointers are deduced to the plain non-reference type (i.e. to | |
114 | plain function pointer). Example: | |
115 | ||
116 | void f(int i); | |
117 | ... | |
118 | __make_list__(&f); | |
119 | ||
120 | creates a __list__ of type | |
121 | ||
122 | __list__<void (*)(int)> | |
123 | ||
124 | [heading Reference Wrappers] | |
125 | ||
126 | Fusion's generation functions (e.g. __make_list__) by default stores the | |
127 | element types as plain non-reference types. Example: | |
128 | ||
129 | void foo(const A& a, B& b) { | |
130 | ... | |
131 | __make_list__(a, b) | |
132 | ||
133 | creates a __list__ of type | |
134 | ||
135 | __list__<A, B> | |
136 | ||
137 | Sometimes the plain non-reference type is not desired. You can use | |
138 | `boost::ref` and `boost::cref` to store references or const references | |
139 | (respectively) instead. The mechanism does not compromise const correctness | |
140 | since a const object wrapped with ref results in a tuple element with const | |
141 | reference type (see the fifth code line below). Examples: | |
142 | ||
143 | For example: | |
144 | ||
145 | A a; B b; const A ca = a; | |
146 | __make_list__(cref(a), b); // creates list<const A&, B> | |
147 | __make_list__(ref(a), b); // creates list<A&, B> | |
148 | __make_list__(ref(a), cref(b)); // creates list<A&, const B&> | |
149 | __make_list__(cref(ca)); // creates list<const A&> | |
150 | __make_list__(ref(ca)); // creates list<const A&> | |
151 | ||
152 | See __boost_ref__ for details. | |
153 | ||
154 | Since C++11, the standard reference wrappers (`std::ref` and `std::cref`) work as well. | |
155 | ||
156 | [heading adt_attribute_proxy] | |
157 | ||
158 | To adapt arbitrary data types that do not allow direct access to their members, | |
159 | but allow indirect access via expressions (such as invocations of get- and | |
160 | set-methods), fusion's [^BOOST\_FUSION\_ADAPT\_['xxx]ADT['xxx]]-family (e.g. | |
161 | __adapt_adt__) may be used. | |
162 | To bypass the restriction of not having actual lvalues that | |
163 | represent the elements of the fusion sequence, but rather a sequence of paired | |
164 | expressions that access the elements, the actual return type of fusion's | |
165 | intrinsic sequence access functions (__at__, __at_c__, __at_key__, __deref__, | |
166 | and __deref_data__) is a proxy type, an instance of | |
167 | `adt_attribute_proxy`, that encapsulates these expressions. | |
168 | ||
169 | `adt_attribute_proxy` is defined in the namespace `boost::fusion::extension` and | |
170 | has three template arguments: | |
171 | ||
172 | namespace boost { namespace fusion { namespace extension | |
173 | { | |
174 | template< | |
175 | typename Type | |
176 | , int Index | |
177 | , bool Const | |
178 | > | |
179 | struct adt_attribute_proxy; | |
180 | }}} | |
181 | ||
182 | When adapting a class type, `adt_attribute_proxy` is specialized for every | |
183 | element of the adapted sequence, with `Type` being the class type that is | |
184 | adapted, `Index` the 0-based indices of the elements, and `Const` both `true` | |
185 | and `false`. The return type of fusion's intrinsic sequence access functions | |
186 | for the ['N]th element of an adapted class type `type_name` is | |
187 | [^adt_attribute_proxy<type_name, ['N], ['Const]>], with [^['Const]] being `true` | |
188 | for constant instances of `type_name` and `false` for non-constant ones. | |
189 | ||
190 | [variablelist Notation | |
191 | [[`type_name`] | |
192 | [The type to be adapted, with M attributes]] | |
193 | [[`inst`] | |
194 | [Object of type `type_name`]] | |
195 | [[`const_inst`] | |
196 | [Object of type `type_name const`]] | |
197 | [[[^(attribute_type['N], attribute_const_type['N], get_expr['N], set_expr['N])]] | |
198 | [Attribute descriptor of the ['N]th attribute of `type_name` as passed to the adaption macro, 0\u2264['N]<M]] | |
199 | [[[^proxy_type['N]]] | |
200 | [[^adt_attribute_proxy<type_name, ['N], `false`>] with ['N] being an integral constant, 0\u2264['N]<M]] | |
201 | [[[^const_proxy_type['N]]] | |
202 | [[^adt_attribute_proxy<type_name, ['N], `true`>] with ['N] being an integral constant, 0\u2264['N]<M]] | |
203 | [[[^proxy['N]]] | |
204 | [Object of type [^proxy_type['N]]]] | |
205 | [[[^const_proxy['N]]] | |
206 | [Object of type [^const_proxy_type['N]]]] | |
207 | ] | |
208 | ||
209 | [*Expression Semantics] | |
210 | ||
211 | [table | |
212 | [[Expression] [Semantics]] | |
213 | [[[^proxy_type['N](inst)]] [Creates an instance of [^proxy_type['N]] with underlying object `inst`]] | |
214 | [[[^const_proxy_type['N](const_inst)]] [Creates an instance of [^const_proxy_type['N]] with underlying object `const_inst`]] | |
215 | [[[^proxy_type['N]::type]] [Another name for [^attribute_type['N]]]] | |
216 | [[[^const_proxy_type['N]::type]] [Another name for [^const_attribute_type['N]]]] | |
217 | [[[^proxy['N]=t]] [Invokes [^set_expr['N]], with `t` being an arbitrary object. [^set_expr['N]] may access the variables named `obj` of type `type_name&`, which represent the corresponding instance of `type_name`, and `val` of an arbitrary const-qualified reference template type parameter `Val`, which represents `t`.]] | |
218 | [[[^proxy['N].get()]] [Invokes [^get_expr['N]] and forwards its return value. [^get_expr['N]] may access the variable named `obj` of type `type_name&` which represents the underlying instance of `type_name`. [^attribute_type['N]] may specify the type that [^get_expr['N]] denotes to.]] | |
219 | [[[^const_proxy['N].get()]] [Invokes [^get_expr['N]] and forwards its return value. [^get_expr['N]] may access the variable named `obj` of type `type_name const&` which represents the underlying instance of `type_name`. [^attribute_const_type['N]] may specify the type that [^get_expr['N]] denotes to.]] | |
220 | ] | |
221 | ||
222 | Additionally, [^proxy_type['N]] and [^const_proxy_type['N]] are copy | |
223 | constructible, copy assignable and implicitly convertible to | |
224 | [^proxy_type['N]::type] or [^const_proxy_type['N]::type]. | |
225 | ||
226 | [tip To avoid the pitfalls of the proxy type, an arbitrary class type may also | |
227 | be adapted directly using fusion's [link fusion.extension intrinsic extension | |
228 | mechanism].] | |
229 | ||
230 | [endsect] | |
231 |