1 ///////////////////////////////////////////////////////////////////////////////
2 /// \file extends.hpp
3 /// Macros and a base class for defining end-user expression types
4 //
5 //  Copyright 2008 Eric Niebler. Distributed under the Boost
6 //  Software License, Version 1.0. (See accompanying file
7 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 
9 #ifndef BOOST_PROTO_EXTENDS_HPP_EAN_11_1_2006
10 #define BOOST_PROTO_EXTENDS_HPP_EAN_11_1_2006
11 
12 #include <cstddef> // for offsetof
13 #include <boost/config.hpp>
14 #include <boost/detail/workaround.hpp>
15 #include <boost/preprocessor/facilities/empty.hpp>
16 #include <boost/preprocessor/tuple/elem.hpp>
17 #include <boost/preprocessor/control/if.hpp>
18 #include <boost/preprocessor/arithmetic/inc.hpp>
19 #include <boost/preprocessor/arithmetic/dec.hpp>
20 #include <boost/preprocessor/iteration/local.hpp>
21 #include <boost/preprocessor/repetition/enum_params.hpp>
22 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
23 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
24 #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
25 #include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp>
26 #include <boost/preprocessor/seq/for_each.hpp>
27 #include <boost/utility/addressof.hpp>
28 #include <boost/utility/result_of.hpp>
29 #include <boost/proto/proto_fwd.hpp>
30 #include <boost/proto/traits.hpp>
31 #include <boost/proto/expr.hpp>
32 #include <boost/proto/args.hpp>
33 #include <boost/proto/traits.hpp>
34 #include <boost/proto/generate.hpp>
35 
36 #ifdef _MSC_VER
37 #define BOOST_PROTO_DISABLE_MSVC_C4522 __pragma(warning(disable: 4522))
38 #else
39 #define BOOST_PROTO_DISABLE_MSVC_C4522
40 #endif
41 
42 namespace boost { namespace proto
43 {
44     #ifdef __GNUC__
45     /// INTERNAL ONLY
46     ///
47     # define BOOST_PROTO_ADDROF(x) ((char const volatile*)boost::addressof(x))
48     /// INTERNAL ONLY
49     ///
50     # define BOOST_PROTO_OFFSETOF(s,m) (BOOST_PROTO_ADDROF((((s *)this)->m)) - BOOST_PROTO_ADDROF(*((s *)this)))
51     #else
52     /// INTERNAL ONLY
53     ///
54     # define BOOST_PROTO_OFFSETOF offsetof
55     #endif
56 
57     /// INTERNAL ONLY
58     ///
59     #define BOOST_PROTO_CONST() const
60 
61     /// INTERNAL ONLY
62     ///
63     #define BOOST_PROTO_TYPENAME() typename
64 
65     /// INTERNAL ONLY
66     ///
67     #define BOOST_PROTO_TEMPLATE_YES_(Z, N) template<BOOST_PP_ENUM_PARAMS_Z(Z, N, typename A)>
68 
69     /// INTERNAL ONLY
70     ///
71     #define BOOST_PROTO_TEMPLATE_NO_(Z, N)
72 
73     /// INTERNAL ONLY
74     ///
75     #define BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, Const)                                      \
76         BOOST_PP_IF(N, BOOST_PROTO_TEMPLATE_YES_, BOOST_PROTO_TEMPLATE_NO_)(Z, N)                   \
77         typename BOOST_PROTO_RESULT_OF<                                                             \
78             proto_generator(                                                                        \
79                 typename boost::proto::result_of::BOOST_PP_CAT(funop, N)<                           \
80                     proto_derived_expr Const()                                                      \
81                   , proto_domain                                                                    \
82                     BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, const A)                                  \
83                 >::type                                                                             \
84             )                                                                                       \
85         >::type const                                                                               \
86         operator ()(BOOST_PP_ENUM_BINARY_PARAMS_Z(Z, N, A, const &a)) Const()                       \
87         {                                                                                           \
88             typedef boost::proto::result_of::BOOST_PP_CAT(funop, N)<                                \
89                 proto_derived_expr Const()                                                          \
90               , proto_domain                                                                        \
91                 BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, const A)                                      \
92             > funop;                                                                                \
93             return proto_generator()(                                                               \
94                 funop::call(                                                                        \
95                     *static_cast<proto_derived_expr Const() *>(this)                                \
96                     BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, a)                                        \
97                 )                                                                                   \
98             );                                                                                      \
99         }                                                                                           \
100         /**/
101 
102     /// INTERNAL ONLY
103     ///
104     #define BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(Const)                                         \
105         template<typename... A>                                                                     \
106         typename BOOST_PROTO_RESULT_OF<                                                             \
107             proto_generator(                                                                        \
108                 typename boost::proto::result_of::funop<                                            \
109                     proto_derived_expr Const()(A const &...)                                        \
110                   , proto_derived_expr                                                              \
111                   , proto_domain                                                                    \
112                 >::type                                                                             \
113             )                                                                                       \
114         >::type const                                                                               \
115         operator ()(A const &...a) Const()                                                          \
116         {                                                                                           \
117             typedef boost::proto::result_of::funop<                                                 \
118                 proto_derived_expr Const()(A const &...)                                            \
119               , proto_derived_expr                                                                  \
120               , proto_domain                                                                        \
121             > funop;                                                                                \
122             return proto_generator()(                                                               \
123                 funop::call(                                                                        \
124                     *static_cast<proto_derived_expr Const() *>(this)                                \
125                   , a...                                                                            \
126                 )                                                                                   \
127             );                                                                                      \
128         }                                                                                           \
129         /**/
130 
131     /// INTERNAL ONLY
132     ///
133     #define BOOST_PROTO_DEFINE_FUN_OP_CONST(Z, N, DATA)                                             \
134         BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, BOOST_PROTO_CONST)                              \
135         /**/
136 
137     /// INTERNAL ONLY
138     ///
139     #define BOOST_PROTO_DEFINE_FUN_OP_NON_CONST(Z, N, DATA)                                         \
140         BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, BOOST_PP_EMPTY)                                 \
141         /**/
142 
143     /// INTERNAL ONLY
144     ///
145     #define BOOST_PROTO_DEFINE_FUN_OP(Z, N, DATA)                                                   \
146         BOOST_PROTO_DEFINE_FUN_OP_CONST(Z, N, DATA)                                                 \
147         BOOST_PROTO_DEFINE_FUN_OP_NON_CONST(Z, N, DATA)                                             \
148         /**/
149 
150     /// INTERNAL ONLY
151     ///
152     #define BOOST_PROTO_EXTENDS_CHILD(Z, N, DATA)                                                   \
153         typedef                                                                                     \
154             typename proto_base_expr::BOOST_PP_CAT(proto_child, N)                                  \
155         BOOST_PP_CAT(proto_child, N);                                                               \
156         /**/
157 
158     #define BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, Domain)                                       \
159         Expr proto_expr_;                                                                           \
160                                                                                                     \
161         typedef Expr proto_base_expr_; /**< INTERNAL ONLY */                                        \
162         typedef typename proto_base_expr_::proto_base_expr proto_base_expr;                         \
163         typedef Domain proto_domain;                                                                \
164         typedef Derived proto_derived_expr;                                                         \
165         typedef typename proto_base_expr::proto_tag proto_tag;                                      \
166         typedef typename proto_base_expr::proto_args proto_args;                                    \
167         typedef typename proto_base_expr::proto_arity proto_arity;                                  \
168         typedef typename proto_base_expr::proto_grammar proto_grammar;                              \
169         typedef typename proto_base_expr::address_of_hack_type_ proto_address_of_hack_type_;        \
170         typedef void proto_is_expr_; /**< INTERNAL ONLY */                                          \
171         static const long proto_arity_c = proto_base_expr::proto_arity_c;                \
172         typedef boost::proto::tag::proto_expr fusion_tag;                                           \
173         BOOST_PP_REPEAT(BOOST_PROTO_MAX_ARITY, BOOST_PROTO_EXTENDS_CHILD, ~)                        \
174                                                                                                     \
175         static proto_derived_expr const make(Expr const &e)                                         \
176         {                                                                                           \
177             proto_derived_expr that = {e};                                                          \
178             return that;                                                                            \
179         }                                                                                           \
180                                                                                                     \
181         proto_base_expr &proto_base()                                                               \
182         {                                                                                           \
183             return this->proto_expr_.proto_base();                                                  \
184         }                                                                                           \
185                                                                                                     \
186         proto_base_expr const &proto_base() const                                                   \
187         {                                                                                           \
188             return this->proto_expr_.proto_base();                                                  \
189         }                                                                                           \
190                                                                                                     \
191         operator proto_address_of_hack_type_() const                                                \
192         {                                                                                           \
193             return boost::addressof(this->proto_base().child0);                                     \
194         }                                                                                           \
195         /**/
196 
197     #define BOOST_PROTO_BASIC_EXTENDS(Expr, Derived, Domain)                                        \
198         BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, Domain)                                           \
199         typedef void proto_is_aggregate_;                                                           \
200         typedef Domain::proto_generator proto_generator;                                            \
201         /**< INTERNAL ONLY */
202 
203     #define BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, Const, Typename)                            \
204         BOOST_PROTO_DISABLE_MSVC_C4522                                                              \
205         Typename() BOOST_PROTO_RESULT_OF<                                                           \
206             Typename() This::proto_generator(                                                       \
207                 Typename() boost::proto::base_expr<                                                 \
208                     Typename() This::proto_domain                                                   \
209                   , boost::proto::tag::assign                                                       \
210                   , boost::proto::list2<                                                            \
211                         This &                                                                      \
212                       , This Const() &                                                              \
213                     >                                                                               \
214                 >::type                                                                             \
215             )                                                                                       \
216         >::type const                                                                               \
217         operator =(This Const() &a)                                                                 \
218         {                                                                                           \
219             typedef                                                                                 \
220                 Typename() boost::proto::base_expr<                                                 \
221                     Typename() This::proto_domain                                                   \
222                   , boost::proto::tag::assign                                                       \
223                   , boost::proto::list2<                                                            \
224                         This &                                                                      \
225                       , This Const() &                                                              \
226                     >                                                                               \
227                 >::type                                                                             \
228             that_type;                                                                              \
229             that_type const that = {                                                                \
230                 *this                                                                               \
231               , a                                                                                   \
232             };                                                                                      \
233             return Typename() This::proto_generator()(that);                                        \
234         }                                                                                           \
235         /**/
236 
237         // MSVC 8.0 and higher seem to need copy-assignment operator to be overloaded on *both*
238         // const and non-const rhs arguments.
239     #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) && (BOOST_MSVC > 1310)
240         #define BOOST_PROTO_EXTENDS_COPY_ASSIGN_(This, Typename)                                    \
241             BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, BOOST_PP_EMPTY, Typename)                   \
242             BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, BOOST_PROTO_CONST, Typename)                \
243             /**/
244     #else
245         #define BOOST_PROTO_EXTENDS_COPY_ASSIGN_(This, Typename)                                    \
246             BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, BOOST_PROTO_CONST, Typename)                \
247             /**/
248     #endif
249 
250         /// INTERNAL ONLY
251         ///
252     #define BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(ThisConst, ThatConst)                                  \
253         template<typename A>                                                                        \
254         typename BOOST_PROTO_RESULT_OF<                                                             \
255             proto_generator(                                                                        \
256                 typename boost::proto::base_expr<                                                   \
257                     proto_domain                                                                    \
258                   , boost::proto::tag::assign                                                       \
259                   , boost::proto::list2<                                                            \
260                         proto_derived_expr ThisConst() &                                            \
261                       , typename boost::proto::result_of::as_child<A ThatConst(), proto_domain>::type \
262                     >                                                                               \
263                 >::type                                                                             \
264             )                                                                                       \
265         >::type const                                                                               \
266         operator =(A ThatConst() &a) ThisConst()                                                    \
267         {                                                                                           \
268             typedef                                                                                 \
269                 typename boost::proto::base_expr<                                                   \
270                     proto_domain                                                                    \
271                   , boost::proto::tag::assign                                                       \
272                   , boost::proto::list2<                                                            \
273                         proto_derived_expr ThisConst() &                                            \
274                       , typename boost::proto::result_of::as_child<A ThatConst(), proto_domain>::type \
275                     >                                                                               \
276                 >::type                                                                             \
277             that_type;                                                                              \
278             that_type const that = {                                                                \
279                 *static_cast<proto_derived_expr ThisConst() *>(this)                                \
280               , boost::proto::as_child<proto_domain>(a)                                             \
281             };                                                                                      \
282             return proto_generator()(that);                                                         \
283         }                                                                                           \
284         /**/
285 
286     #define BOOST_PROTO_EXTENDS_ASSIGN_CONST_()                                                     \
287         BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PROTO_CONST, BOOST_PP_EMPTY)                         \
288         BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PROTO_CONST, BOOST_PROTO_CONST)                      \
289         /**/
290 
291     #define BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST_()                                                 \
292         BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PP_EMPTY, BOOST_PP_EMPTY)                            \
293         BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PP_EMPTY, BOOST_PROTO_CONST)                         \
294         /**/
295 
296     #define BOOST_PROTO_EXTENDS_ASSIGN_()                                                           \
297         BOOST_PROTO_EXTENDS_ASSIGN_CONST_()                                                         \
298         BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST_()                                                     \
299         /**/
300 
301     #define BOOST_PROTO_EXTENDS_ASSIGN_CONST()                                                      \
302         BOOST_PROTO_EXTENDS_COPY_ASSIGN_(proto_derived_expr, BOOST_PROTO_TYPENAME)                  \
303         BOOST_PROTO_EXTENDS_ASSIGN_CONST_()                                                         \
304         /**/
305 
306     #define BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST()                                                  \
307         BOOST_PROTO_EXTENDS_COPY_ASSIGN_(proto_derived_expr, BOOST_PROTO_TYPENAME)                  \
308         BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST_()                                                     \
309         /**/
310 
311     #define BOOST_PROTO_EXTENDS_ASSIGN()                                                            \
312         BOOST_PROTO_EXTENDS_COPY_ASSIGN_(proto_derived_expr, BOOST_PROTO_TYPENAME)                  \
313         BOOST_PROTO_EXTENDS_ASSIGN_()                                                               \
314         /**/
315 
316         /// INTERNAL ONLY
317         ///
318     #define BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(ThisConst, ThatConst)                               \
319         template<typename A>                                                                        \
320         typename BOOST_PROTO_RESULT_OF<                                                             \
321             proto_generator(                                                                        \
322                 typename boost::proto::base_expr<                                                   \
323                     proto_domain                                                                    \
324                   , boost::proto::tag::subscript                                                    \
325                   , boost::proto::list2<                                                            \
326                         proto_derived_expr ThisConst() &                                            \
327                       , typename boost::proto::result_of::as_child<A ThatConst(), proto_domain>::type \
328                     >                                                                               \
329                 >::type                                                                             \
330             )                                                                                       \
331         >::type const                                                                               \
332         operator [](A ThatConst() &a) ThisConst()                                                   \
333         {                                                                                           \
334             typedef                                                                                 \
335                 typename boost::proto::base_expr<                                                   \
336                     proto_domain                                                                    \
337                   , boost::proto::tag::subscript                                                    \
338                   , boost::proto::list2<                                                            \
339                         proto_derived_expr ThisConst() &                                            \
340                       , typename boost::proto::result_of::as_child<A ThatConst(), proto_domain>::type \
341                     >                                                                               \
342                 >::type                                                                             \
343             that_type;                                                                              \
344             that_type const that = {                                                                \
345                 *static_cast<proto_derived_expr ThisConst() *>(this)                                \
346               , boost::proto::as_child<proto_domain>(a)                                             \
347             };                                                                                      \
348             return proto_generator()(that);                                                         \
349         }                                                                                           \
350         /**/
351 
352     #define BOOST_PROTO_EXTENDS_SUBSCRIPT_CONST()                                                   \
353         BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PROTO_CONST, BOOST_PP_EMPTY)                      \
354         BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PROTO_CONST, BOOST_PROTO_CONST)                   \
355         /**/
356 
357     #define BOOST_PROTO_EXTENDS_SUBSCRIPT_NON_CONST()                                               \
358         BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PP_EMPTY, BOOST_PP_EMPTY)                         \
359         BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PP_EMPTY, BOOST_PROTO_CONST)                      \
360         /**/
361 
362     #define BOOST_PROTO_EXTENDS_SUBSCRIPT()                                                         \
363         BOOST_PROTO_EXTENDS_SUBSCRIPT_CONST()                                                       \
364         BOOST_PROTO_EXTENDS_SUBSCRIPT_NON_CONST()                                                   \
365         /**/
366 
367         /// INTERNAL ONLY
368         ///
369     #define BOOST_PROTO_EXTENDS_FUNCTION_()                                                         \
370         template<typename Sig>                                                                      \
371         struct result                                                                               \
372         {                                                                                           \
373             typedef                                                                                 \
374                 typename BOOST_PROTO_RESULT_OF<                                                     \
375                     proto_generator(                                                                \
376                         typename boost::proto::result_of::funop<                                    \
377                             Sig                                                                     \
378                           , proto_derived_expr                                                      \
379                           , proto_domain                                                            \
380                         >::type                                                                     \
381                     )                                                                               \
382                 >::type const                                                                       \
383             type;                                                                                   \
384         };                                                                                          \
385         /**/
386 
387     #ifndef BOOST_NO_VARIADIC_TEMPLATES
388         #define BOOST_PROTO_EXTENDS_FUNCTION_CONST()                                                \
389             BOOST_PROTO_EXTENDS_FUNCTION_()                                                         \
390             BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PROTO_CONST)                             \
391             /**/
392 
393         #define BOOST_PROTO_EXTENDS_FUNCTION_NON_CONST()                                            \
394             BOOST_PROTO_EXTENDS_FUNCTION_()                                                         \
395             BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PP_EMPTY)                                \
396             /**/
397 
398         #define BOOST_PROTO_EXTENDS_FUNCTION()                                                      \
399             BOOST_PROTO_EXTENDS_FUNCTION_()                                                         \
400             BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PP_EMPTY)                                \
401             BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PROTO_CONST)                             \
402             /**/
403     #else
404         #define BOOST_PROTO_EXTENDS_FUNCTION_CONST()                                                \
405             BOOST_PROTO_EXTENDS_FUNCTION_()                                                         \
406             BOOST_PP_REPEAT_FROM_TO(                                                                \
407                 0                                                                                   \
408               , BOOST_PROTO_MAX_FUNCTION_CALL_ARITY                                                 \
409               , BOOST_PROTO_DEFINE_FUN_OP_CONST                                                     \
410               , ~                                                                                   \
411             )                                                                                       \
412             /**/
413 
414         #define BOOST_PROTO_EXTENDS_FUNCTION_NON_CONST()                                            \
415             BOOST_PROTO_EXTENDS_FUNCTION_()                                                         \
416             BOOST_PP_REPEAT_FROM_TO(                                                                \
417                 0                                                                                   \
418               , BOOST_PROTO_MAX_FUNCTION_CALL_ARITY                                                 \
419               , BOOST_PROTO_DEFINE_FUN_OP_NON_CONST                                                 \
420               , ~                                                                                   \
421             )                                                                                       \
422             /**/
423 
424         #define BOOST_PROTO_EXTENDS_FUNCTION()                                                      \
425             BOOST_PROTO_EXTENDS_FUNCTION_()                                                         \
426             BOOST_PP_REPEAT_FROM_TO(                                                                \
427                 0                                                                                   \
428               , BOOST_PROTO_MAX_FUNCTION_CALL_ARITY                                                 \
429               , BOOST_PROTO_DEFINE_FUN_OP                                                           \
430               , ~                                                                                   \
431             )                                                                                       \
432             /**/
433     #endif
434 
435     #define BOOST_PROTO_EXTENDS(Expr, Derived, Domain)                                              \
436         BOOST_PROTO_BASIC_EXTENDS(Expr, Derived, Domain)                                            \
437         BOOST_PROTO_EXTENDS_ASSIGN()                                                                \
438         BOOST_PROTO_EXTENDS_SUBSCRIPT()                                                             \
439         BOOST_PROTO_EXTENDS_FUNCTION()                                                              \
440         /**/
441 
442     #define BOOST_PROTO_EXTENDS_USING_ASSIGN(Derived)                                               \
443         typedef typename Derived::proto_extends proto_extends;                                      \
444         using proto_extends::operator =;                                                            \
445         BOOST_PROTO_EXTENDS_COPY_ASSIGN_(Derived, BOOST_PROTO_TYPENAME)                             \
446         /**/
447 
448     #define BOOST_PROTO_EXTENDS_USING_ASSIGN_NON_DEPENDENT(Derived)                                 \
449         typedef Derived::proto_extends proto_extends;                                               \
450         using proto_extends::operator =;                                                            \
451         BOOST_PROTO_EXTENDS_COPY_ASSIGN_(Derived, BOOST_PP_EMPTY)                                   \
452         /**/
453 
454     namespace exprns_
455     {
456         /// \brief Empty type to be used as a dummy template parameter of
457         ///     POD expression wrappers. It allows argument-dependent lookup
458         ///     to find Proto's operator overloads.
459         ///
460         /// \c proto::is_proto_expr allows argument-dependent lookup
461         ///     to find Proto's operator overloads. For example:
462         ///
463         /// \code
464         /// template<typename T, typename Dummy = proto::is_proto_expr>
465         /// struct my_terminal
466         /// {
467         ///     BOOST_PROTO_BASIC_EXTENDS(
468         ///         typename proto::terminal<T>::type
469         ///       , my_terminal<T>
470         ///       , default_domain
471         ///     )
472         /// };
473         ///
474         /// // ...
475         /// my_terminal<int> _1, _2;
476         /// _1 + _2; // OK, uses proto::operator+
477         /// \endcode
478         ///
479         /// Without the second \c Dummy template parameter, Proto's operator
480         /// overloads would not be considered by name lookup.
481         struct is_proto_expr
482         {};
483 
484         /// \brief extends\<\> class template for adding behaviors to a Proto expression template
485         ///
486         template<
487             typename Expr
488           , typename Derived
489           , typename Domain     // = proto::default_domain
490           , long Arity          // = Expr::proto_arity_c
491         >
492         struct extends
493         {
extendsboost::proto::exprns_::extends494             extends()
495               : proto_expr_()
496             {}
497 
extendsboost::proto::exprns_::extends498             extends(extends const &that)
499               : proto_expr_(that.proto_expr_)
500             {}
501 
extendsboost::proto::exprns_::extends502             extends(Expr const &expr_)
503               : proto_expr_(expr_)
504             {}
505 
506             typedef extends proto_extends;
507             BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, Domain)
508             typedef typename Domain::proto_generator proto_generator;
509             BOOST_PROTO_EXTENDS_ASSIGN_CONST_()
510             BOOST_PROTO_EXTENDS_SUBSCRIPT_CONST()
511 
512             // Instead of using BOOST_PROTO_EXTENDS_FUNCTION, which uses
513             // nested preprocessor loops, use file iteration here to generate
514             // the operator() overloads, which is more efficient.
515             #include <boost/proto/detail/extends_funop_const.hpp>
516         };
517 
518         /// \brief extends\<\> class template for adding behaviors to a Proto expression template
519         ///
520         template<typename Expr, typename Derived, typename Domain>
521         struct extends<Expr, Derived, Domain, 0>
522         {
extendsboost::proto::exprns_::extends523             extends()
524               : proto_expr_()
525             {}
526 
extendsboost::proto::exprns_::extends527             extends(extends const &that)
528               : proto_expr_(that.proto_expr_)
529             {}
530 
extendsboost::proto::exprns_::extends531             extends(Expr const &expr_)
532               : proto_expr_(expr_)
533             {}
534 
535             typedef extends proto_extends;
536             BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, Domain)
537             typedef typename Domain::proto_generator proto_generator;
538             BOOST_PROTO_EXTENDS_ASSIGN_()
539             BOOST_PROTO_EXTENDS_SUBSCRIPT()
540 
541             // Instead of using BOOST_PROTO_EXTENDS_FUNCTION, which uses
542             // nested preprocessor loops, use file iteration here to generate
543             // the operator() overloads, which is more efficient.
544             #include <boost/proto/detail/extends_funop.hpp>
545         };
546 
547         /// INTERNAL ONLY
548         ///
549         template<typename This, typename Fun, typename Domain>
550         struct virtual_member
551         {
552             typedef Domain proto_domain;
553             typedef typename Domain::proto_generator proto_generator;
554             typedef virtual_member<This, Fun, Domain> proto_derived_expr;
555             typedef tag::member proto_tag;
556             typedef list2<This &, expr<tag::terminal, term<Fun> > const &> proto_args;
557             typedef mpl::long_<2> proto_arity;
558             typedef detail::not_a_valid_type proto_address_of_hack_type_;
559             typedef void proto_is_expr_; /**< INTERNAL ONLY */
560             static const long proto_arity_c = 2;
561             typedef boost::proto::tag::proto_expr fusion_tag;
562             typedef This &proto_child0;
563             typedef expr<tag::terminal, term<Fun> > const &proto_child1;
564             typedef expr<proto_tag, proto_args, proto_arity_c> proto_base_expr;
565             typedef basic_expr<proto_tag, proto_args, proto_arity_c> proto_grammar;
566             typedef void proto_is_aggregate_; /**< INTERNAL ONLY */
567 
568             BOOST_PROTO_EXTENDS_ASSIGN_()
BOOST_PROTO_EXTENDS_SUBSCRIPTboost::proto::exprns_::virtual_member569             BOOST_PROTO_EXTENDS_SUBSCRIPT()
570 
571             // Instead of using BOOST_PROTO_EXTENDS_FUNCTION, which uses
572             // nested preprocessor loops, use file iteration here to generate
573             // the operator() overloads, which is more efficient.
574             #define BOOST_PROTO_NO_WAVE_OUTPUT
575             #include <boost/proto/detail/extends_funop.hpp>
576             #undef BOOST_PROTO_NO_WAVE_OUTPUT
577 
578             proto_base_expr const proto_base() const
579             {
580                 proto_base_expr that = {this->child0(), this->child1()};
581                 return that;
582             }
583 
child0boost::proto::exprns_::virtual_member584             proto_child0 child0() const
585             {
586                 using std::size_t;
587                 return *(This *)((char *)this - BOOST_PROTO_OFFSETOF(This, proto_member_union_start_));
588             }
589 
child1boost::proto::exprns_::virtual_member590             proto_child1 child1() const
591             {
592                 static expr<tag::terminal, term<Fun>, 0> const that = {Fun()};
593                 return that;
594             }
595         };
596 
597         /// INTERNAL ONLY
598         ///
599         #define BOOST_PROTO_EXTENDS_MEMBER_(R, DOMAIN, ELEM)                                            \
600             boost::proto::exprns_::virtual_member<                                                      \
601                 proto_derived_expr                                                                      \
602               , BOOST_PP_TUPLE_ELEM(2, 0, ELEM)                                                         \
603               , DOMAIN                                                                                  \
604             > BOOST_PP_TUPLE_ELEM(2, 1, ELEM);                                                          \
605             /**/
606 
607         /// \brief For declaring virtual data members in an extension class.
608         ///
609         #define BOOST_PROTO_EXTENDS_MEMBERS_WITH_DOMAIN(SEQ, DOMAIN)                                    \
610             union                                                                                       \
611             {                                                                                           \
612                 char proto_member_union_start_;                                                         \
613                 BOOST_PP_SEQ_FOR_EACH(BOOST_PROTO_EXTENDS_MEMBER_, DOMAIN, SEQ)                         \
614             };                                                                                          \
615             /**/
616 
617         /// \brief For declaring virtual data members in an extension class.
618         ///
619         #define BOOST_PROTO_EXTENDS_MEMBERS(SEQ)                                                        \
620             BOOST_PROTO_EXTENDS_MEMBERS_WITH_DOMAIN(SEQ, proto_domain)                                  \
621             /**/
622 
623     }
624 
625 }}
626 
627 #endif
628