• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<?xml version="1.0" encoding="utf-8"?>
2<!--
3  Copyright 2012 Eric Niebler
4
5  Distributed under the Boost
6  Software License, Version 1.0. (See accompanying
7  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8  -->
9<header name="boost/proto/transform/make.hpp">
10  <para>
11    Contains definition of the
12    <computeroutput>
13      <classname alt="boost::proto::make">proto::make&lt;&gt;</classname>
14    </computeroutput>
15    and
16    <computeroutput>
17      <classname alt="boost::proto::protect">proto::protect&lt;&gt;</classname>
18    </computeroutput>
19    transforms.
20  </para>
21  <namespace name="boost">
22    <namespace name="proto">
23      <struct name="noinvoke">
24        <template>
25          <template-type-parameter name="T"/>
26        </template>
27        <purpose>A type annotation in an <conceptname>ObjectTransform</conceptname> which instructs
28          Proto not to look for a nested <computeroutput>::type</computeroutput> within
29          <computeroutput>T</computeroutput> after type substitution.</purpose>
30        <description>
31          <para>
32            <conceptname>ObjectTransform</conceptname>s are evaluated by
33            <computeroutput><classname alt="proto::make">proto::make&lt;&gt;</classname></computeroutput>,
34            which finds all nested transforms and replaces them with the result of their applications.
35            If any substitutions are performed, the result is first assumed to be a metafunction to be applied;
36            that is, Proto checks to see if the result has a nested <computeroutput>::type</computeroutput>
37            typedef. If it does, that becomes the result. The purpose of <computeroutput>proto::noinvoke&lt;&gt;</computeroutput>
38            is to prevent Proto from looking for a nested <computeroutput>::type</computeroutput> typedef
39            in these situations.
40          </para>
41          <para>
42            Example:
43            <programlisting>struct Test
44  : <classname>proto::when</classname>&lt;
45        <classname>_</classname>
46      , proto::noinvoke&lt;
47            // This remove_pointer invocation is bloked by noinvoke
48            boost::remove_pointer&lt;
49                // This add_pointer invocation is *not* blocked by noinvoke
50                boost::add_pointer&lt;<classname>_</classname>&gt;
51            &gt;
52        &gt;()
53    &gt;
54{};
55
56void test_noinvoke()
57{
58    typedef <classname>proto::terminal</classname>&lt;int&gt;::type Int;
59
60    BOOST_MPL_ASSERT((
61        boost::is_same&lt;
62            boost::result_of&lt;Test(Int)&gt;::type
63          , boost::remove_pointer&lt;Int *&gt;
64        &gt;
65    ));
66
67    Int i = {42};
68    boost::remove_pointer&lt;Int *&gt; t = Test()(i);
69}</programlisting>
70          </para>
71        </description>
72      </struct>
73      <struct name="protect">
74        <template>
75          <template-type-parameter name="PrimitiveTransform"/>
76        </template>
77        <inherit><classname>proto::transform</classname>&lt; protect&lt;PrimitiveTransform&gt; &gt;</inherit>
78        <purpose>A <conceptname>PrimitiveTransform</conceptname> which prevents another
79          <conceptname>PrimitiveTransform</conceptname> from being applied in an
80          <conceptname>ObjectTransform</conceptname>.</purpose>
81        <description>
82          <para>
83            When building higher order transforms with
84            <computeroutput>
85              <classname alt="proto::make">proto::make&lt;&gt;</classname>
86            </computeroutput> or
87            <computeroutput>
88              <classname alt="proto::lazy">proto::lazy&lt;&gt;</classname>
89            </computeroutput>,
90            you sometimes would like to build types that are parameterized with Proto transforms. In such
91            lambda-style transforms, Proto will unhelpfully find all nested transforms and apply them, even
92            if you don't want them to be applied. Consider the following transform, which will replace the
93            <computeroutput>proto::_</computeroutput> in
94            <computeroutput>Bar&lt;proto::_&gt;()</computeroutput>
95            with <computeroutput>proto::terminal&lt;int&gt;::type</computeroutput>:
96          </para>
97          <para>
98            <programlisting>template&lt;typename T&gt;
99struct Bar
100{};
101
102struct Foo :
103  <classname>proto::when</classname>&lt;<classname>proto::_</classname>, Bar&lt;<classname>proto::_</classname>&gt;() &gt;
104{};
105
106<classname>proto::terminal</classname>&lt;int&gt;::type i = {0};
107
108int main() {
109  Foo()(i);
110  std::cout &lt;&lt; typeid(Foo()(i)).name() &lt;&lt; std::endl;
111}</programlisting>
112          </para>
113          <para>
114            If you actually wanted to default-construct an object of type
115            <computeroutput>Bar&lt;proto::_&gt;</computeroutput>, you would have to protect the
116            <computeroutput>_</computeroutput> to prevent it from being applied. You can
117            use <computeroutput>proto::protect&lt;&gt;</computeroutput> as follows:
118          </para>
119          <para>
120            <programlisting>// OK: replace anything with Bar&lt;_&gt;()
121struct Foo :
122  <classname>proto::when</classname>&lt;<classname>proto::_</classname>, Bar&lt;<classname>proto::protect</classname>&lt;<classname>proto::_</classname>&gt; &gt;() &gt;
123{};</programlisting>
124          </para>
125        </description>
126        <struct name="impl">
127          <template>
128            <template-type-parameter name=""/>
129            <template-type-parameter name=""/>
130            <template-type-parameter name=""/>
131          </template>
132          <typedef name="result_type">
133            <type>PrimitiveTransform</type>
134          </typedef>
135        </struct>
136      </struct>
137
138      <struct name="make">
139        <template>
140          <template-type-parameter name="T"/>
141        </template>
142
143        <inherit><classname>proto::transform</classname>&lt; make&lt;T&gt; &gt;</inherit>
144
145        <purpose>A <conceptname>PrimitiveTransform</conceptname> that computes a type by evaluating
146          any nested transforms and then constructs an object of that type. </purpose>
147
148        <description>
149          <para>
150            The purpose of <computeroutput>proto::make&lt;&gt;</computeroutput> is to annotate a transform as
151            an <conceptname>ObjectTransform</conceptname> so that
152            <computeroutput><classname alt="proto::when">proto::when&lt;&gt;</classname></computeroutput> knows
153            how to apply it.
154          </para>
155
156          <para>
157            For the full description of the behavior of the
158            <computeroutput><classname alt="proto::make">proto::make&lt;&gt;</classname></computeroutput>
159            transform, see the documentation for the nested
160            <computeroutput><classname alt="proto::make::impl">proto::make::impl&lt;&gt;</classname></computeroutput>
161            class template.
162          </para>
163        </description>
164
165        <struct name="impl">
166          <template>
167            <template-type-parameter name="Expr"/>
168            <template-type-parameter name="State"/>
169            <template-type-parameter name="Data"/>
170          </template>
171          <inherit><classname>proto::transform_impl</classname>&lt; Expr, State, Data &gt;</inherit>
172          <typedef name="result_type">
173            <type><emphasis>see-below</emphasis></type>
174            <description>
175              <para>
176                <computeroutput><classname>proto::make</classname>&lt;T&gt;::impl&lt;Expr, State, Data&gt;::result_type</computeroutput> is
177                computed as follows:
178              </para>
179              <para>
180                If <computeroutput>T</computeroutput> is an <conceptname>ObjectTransform</conceptname> of the form
181                <computeroutput>Object(A<subscript>0</subscript>,…A<subscript>n</subscript>)</computeroutput> or
182                <computeroutput>Object(A<subscript>0</subscript>,…A<subscript>n</subscript> ...)</computeroutput>,
183                then let <computeroutput>O</computeroutput> be the return type
184                <computeroutput>Object</computeroutput>. Otherwise, let <computeroutput>O</computeroutput>
185                be <computeroutput>T</computeroutput>. The <computeroutput>result_type</computeroutput> typedef is
186                then computed as follows:
187              </para>
188              <para>
189                <itemizedlist>
190                  <listitem>
191                    <para>
192                      If <computeroutput><classname>proto::is_transform</classname>&lt;O&gt;::value</computeroutput> is
193                      <computeroutput>true</computeroutput>, then let the result type be
194                      <computeroutput>
195                        boost::result_of&lt;<classname>proto::when</classname>&lt;<classname>_</classname>, O&gt;(Expr, State, Data)&gt;::type
196                      </computeroutput>.
197                      Note that a substitution took place.
198                    </para>
199                  </listitem>
200                  <listitem>
201                    If <computeroutput>O</computeroutput> is a template like
202                    <computeroutput><classname>proto::noinvoke</classname>&lt;S&lt;X<subscript>0</subscript>,…X<subscript>n</subscript>&gt; &gt;</computeroutput>,
203                    then the result type is calculated as follows:
204                    <itemizedlist>
205                      <listitem>
206                        <para>
207                          For each <computeroutput>i</computeroutput> in
208                          <computeroutput>[0,n]</computeroutput>, let <computeroutput>
209                            X<subscript>i</subscript>'
210                          </computeroutput> be
211                          <computeroutput>
212                            boost::result_of&lt;<classname>proto::make</classname>&lt;X<subscript>i</subscript>&gt;(Expr, State, Data)&gt;::type
213                          </computeroutput>
214                          (which evaluates this procedure recursively). Note that a substitution took place. (In this case,
215                          Proto merely assumes that a substitution took place for the sake of compile-time efficiency. There
216                          would be no reason to use <computeroutput><classname>proto::noinvoke&lt;&gt;</classname></computeroutput>
217                          otherwise.)
218                        </para>
219                      </listitem>
220                      <listitem>
221                        <para>
222                          The result type is
223                          <computeroutput>
224                            S&lt;X<subscript>0</subscript>',…X<subscript>n</subscript>'&gt;
225                          </computeroutput>.
226                        </para>
227                      </listitem>
228                    </itemizedlist>
229                  </listitem>
230                  <listitem>
231                    If <computeroutput>O</computeroutput> is a template like
232                    <computeroutput>S&lt;X<subscript>0</subscript>,…X<subscript>n</subscript>&gt;</computeroutput>,
233                    then the result type is calculated as follows:
234                    <itemizedlist>
235                      <listitem>
236                        <para>
237                          For each <computeroutput>i</computeroutput> in
238                          <computeroutput>[0,n]</computeroutput>, let <computeroutput>
239                            X<subscript>i</subscript>'
240                          </computeroutput> be
241                          <computeroutput>
242                            boost::result_of&lt;<classname>proto::make</classname>&lt;X<subscript>i</subscript>&gt;(Expr, State, Data)&gt;::type
243                          </computeroutput>
244                          (which evaluates this procedure recursively). Note whether any substitutions took place during
245                          this operation.
246                        </para>
247                      </listitem>
248                      <listitem>
249                        <para>
250                          If any substitutions took place in the above step and
251                          <computeroutput>
252                            S&lt;X<subscript>0</subscript>',…X<subscript>n</subscript>'&gt;
253                          </computeroutput> has a nested
254                          <computeroutput>type</computeroutput> typedef, the result type is
255                          <computeroutput>
256                            S&lt;X<subscript>0</subscript>',…X<subscript>n</subscript>'&gt;::type
257                          </computeroutput>.
258                        </para>
259                      </listitem>
260                      <listitem>
261                        <para>
262                          Otherwise, the result type is
263                          <computeroutput>
264                            S&lt;X<subscript>0</subscript>',…X<subscript>n</subscript>'&gt;
265                          </computeroutput>.
266                        </para>
267                      </listitem>
268                    </itemizedlist>
269                  </listitem>
270                  <listitem>
271                    Otherwise, the result type is <computeroutput>O</computeroutput>, and note that no
272                    substitution took place.
273                  </listitem>
274                </itemizedlist>
275              </para>
276              <para>
277                Note that <computeroutput><classname alt="proto::when">proto::when&lt;&gt;</classname></computeroutput> is implemented
278                in terms of <computeroutput><classname alt="proto::call">proto::call&lt;&gt;</classname></computeroutput>
279                and <computeroutput><classname alt="proto::make">proto::make&lt;&gt;</classname></computeroutput>, so the
280                above procedure is evaluated recursively.
281              </para>
282            </description>
283          </typedef>
284          <method-group name="public member functions">
285            <method name="operator()" cv="const">
286              <type>result_type</type>
287              <parameter name="expr">
288                <paramtype>typename impl::expr_param</paramtype>
289              </parameter>
290              <parameter name="state">
291                <paramtype>typename impl::state_param</paramtype>
292              </parameter>
293              <parameter name="data">
294                <paramtype>typename impl::data_param</paramtype>
295              </parameter>
296              <description>
297                <para>
298                  <computeroutput>
299                    <classname>proto::make</classname>&lt;T&gt;::impl&lt;Expr,State,Data&gt;::operator()
300                  </computeroutput>
301                  behaves as follows:
302                </para>
303                <para>
304                  <itemizedlist>
305                    <listitem>
306                      <para>
307                        If <computeroutput>T</computeroutput> is of the form
308                        <computeroutput>O(A<subscript>0</subscript>,…A<subscript>n</subscript>)</computeroutput>, then:
309                      </para>
310                      <itemizedlist>
311                        <listitem>
312                          <para>
313                            If <computeroutput>
314                              <classname>proto::is_aggregate</classname>&lt;result_type&gt;::value
315                            </computeroutput> is <computeroutput>true</computeroutput>, then construct
316                            and return an object <computeroutput>that</computeroutput> as follows:
317                            <programlisting>result_type that = {
318  <classname>proto::when</classname>&lt;<classname>_</classname>, A<subscript>0</subscript>&gt;()(expr, state, data),
319320  <classname>proto::when</classname>&lt;<classname>_</classname>, A<subscript>n</subscript>&gt;()(expr, state, data)
321};</programlisting>
322                          </para>
323                        </listitem>
324                        <listitem>
325                          <para>
326                            Otherwise, construct
327                            and return an object <computeroutput>that</computeroutput> as follows:
328                            <programlisting>result_type that(
329  <classname>proto::when</classname>&lt;<classname>_</classname>, A<subscript>0</subscript>&gt;()(expr, state, data),
330331  <classname>proto::when</classname>&lt;<classname>_</classname>, A<subscript>n</subscript>&gt;()(expr, state, data)
332);</programlisting>
333                          </para>
334                        </listitem>
335                      </itemizedlist>
336                    </listitem>
337                    <listitem>
338                      <para>
339                        If <computeroutput>T</computeroutput> is of the form
340                        <computeroutput>O(A<subscript>0</subscript>,…A<subscript>n</subscript> ...)</computeroutput>,
341                        then let <computeroutput>T&apos;</computeroutput> be <computeroutput>O(A<subscript>0</subscript>,…A<subscript>n-1</subscript>, <replaceable>S</replaceable>)</computeroutput>,
342                        where <replaceable>S</replaceable> is a type sequence computed from the unpacking expression <computeroutput>A<subscript>n</subscript></computeroutput>
343                        as described in the reference for <computeroutput><classname>proto::pack</classname></computeroutput>. Then, return:
344                        <programlisting>proto::make&lt;T&apos;&gt;()(expr, state, data)</programlisting>
345                      </para>
346                    </listitem>
347                    <listitem>
348                      <para>
349                        Otherwise, construct and return an object <computeroutput>that</computeroutput>
350                        as follows: <programlisting>result_type that = result_type();</programlisting>
351                      </para>
352                    </listitem>
353                  </itemizedlist>
354                </para>
355              </description>
356            </method>
357          </method-group>
358        </struct>
359      </struct>
360    </namespace>
361  </namespace>
362</header>
363