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 #include <boost/proto/detail/remove_typename.hpp>
36 
37 #if defined(_MSC_VER)
38 # pragma warning(push)
39 # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined
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         BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                            \
78         typename BOOST_PROTO_RESULT_OF<                                                             \
79             proto_generator(                                                                        \
80                 typename boost::proto::result_of::BOOST_PP_CAT(funop, N)<                           \
81                     proto_derived_expr Const()                                                      \
82                   , proto_domain                                                                    \
83                     BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, const A)                                  \
84                 >::type                                                                             \
85             )                                                                                       \
86         >::type const                                                                               \
87         operator ()(BOOST_PP_ENUM_BINARY_PARAMS_Z(Z, N, A, const &a)) Const()                       \
88         {                                                                                           \
89             typedef boost::proto::result_of::BOOST_PP_CAT(funop, N)<                                \
90                 proto_derived_expr Const()                                                          \
91               , proto_domain                                                                        \
92                 BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, const A)                                      \
93             > funop;                                                                                \
94             return proto_generator()(                                                               \
95                 funop::call(                                                                        \
96                     *static_cast<proto_derived_expr Const() *>(this)                                \
97                     BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, a)                                        \
98                 )                                                                                   \
99             );                                                                                      \
100         }                                                                                           \
101         /**/
102 
103     /// INTERNAL ONLY
104     ///
105     #define BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(Const)                                         \
106         template<typename... A>                                                                     \
107         BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                            \
108         typename BOOST_PROTO_RESULT_OF<                                                             \
109             proto_generator(                                                                        \
110                 typename boost::proto::result_of::funop<                                            \
111                     proto_derived_expr Const()(A const &...)                                        \
112                   , proto_derived_expr                                                              \
113                   , proto_domain                                                                    \
114                 >::type                                                                             \
115             )                                                                                       \
116         >::type const                                                                               \
117         operator ()(A const &...a) Const()                                                          \
118         {                                                                                           \
119             typedef boost::proto::result_of::funop<                                                 \
120                 proto_derived_expr Const()(A const &...)                                            \
121               , proto_derived_expr                                                                  \
122               , proto_domain                                                                        \
123             > funop;                                                                                \
124             return proto_generator()(                                                               \
125                 funop::call(                                                                        \
126                     *static_cast<proto_derived_expr Const() *>(this)                                \
127                   , a...                                                                            \
128                 )                                                                                   \
129             );                                                                                      \
130         }                                                                                           \
131         /**/
132 
133     /// INTERNAL ONLY
134     ///
135     #define BOOST_PROTO_DEFINE_FUN_OP_CONST(Z, N, DATA)                                             \
136         BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, BOOST_PROTO_CONST)                              \
137         /**/
138 
139     /// INTERNAL ONLY
140     ///
141     #define BOOST_PROTO_DEFINE_FUN_OP_NON_CONST(Z, N, DATA)                                         \
142         BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, BOOST_PP_EMPTY)                                 \
143         /**/
144 
145     /// INTERNAL ONLY
146     ///
147     #define BOOST_PROTO_DEFINE_FUN_OP(Z, N, DATA)                                                   \
148         BOOST_PROTO_DEFINE_FUN_OP_CONST(Z, N, DATA)                                                 \
149         BOOST_PROTO_DEFINE_FUN_OP_NON_CONST(Z, N, DATA)                                             \
150         /**/
151 
152     /// INTERNAL ONLY
153     ///
154     #define BOOST_PROTO_EXTENDS_CHILD(Z, N, DATA)                                                   \
155         typedef                                                                                     \
156             typename proto_base_expr::BOOST_PP_CAT(proto_child, N)                                  \
157         BOOST_PP_CAT(proto_child, N);                                                               \
158         /**/
159 
160     #define BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, Domain)                                       \
161         Expr proto_expr_;                                                                           \
162                                                                                                     \
163         typedef Expr proto_base_expr_; /**< INTERNAL ONLY */                                        \
164         typedef typename proto_base_expr_::proto_base_expr proto_base_expr;                         \
165         typedef BOOST_PROTO_REMOVE_TYPENAME(Domain) proto_domain;                                   \
166         typedef Derived proto_derived_expr;                                                         \
167         typedef Domain::proto_generator proto_generator;                                            \
168         typedef typename proto_base_expr::proto_tag proto_tag;                                      \
169         typedef typename proto_base_expr::proto_args proto_args;                                    \
170         typedef typename proto_base_expr::proto_arity proto_arity;                                  \
171         typedef typename proto_base_expr::proto_grammar proto_grammar;                              \
172         typedef typename proto_base_expr::address_of_hack_type_ proto_address_of_hack_type_;        \
173         typedef void proto_is_expr_; /**< INTERNAL ONLY */                                          \
174         static const long proto_arity_c = proto_base_expr::proto_arity_c;                           \
175         typedef boost::proto::tag::proto_expr<proto_tag, proto_domain> fusion_tag;                  \
176         BOOST_PP_REPEAT(BOOST_PROTO_MAX_ARITY, BOOST_PROTO_EXTENDS_CHILD, ~)                        \
177                                                                                                     \
178         BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                            \
179         static proto_derived_expr const make(Expr const &e)                                         \
180         {                                                                                           \
181             proto_derived_expr that = {e};                                                          \
182             return that;                                                                            \
183         }                                                                                           \
184                                                                                                     \
185         BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                            \
186         proto_base_expr &proto_base()                                                               \
187         {                                                                                           \
188             return this->proto_expr_.proto_base();                                                  \
189         }                                                                                           \
190                                                                                                     \
191         BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                            \
192         proto_base_expr const &proto_base() const                                                   \
193         {                                                                                           \
194             return this->proto_expr_.proto_base();                                                  \
195         }                                                                                           \
196                                                                                                     \
197         BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                            \
198         operator proto_address_of_hack_type_() const                                                \
199         {                                                                                           \
200             return boost::addressof(this->proto_base().child0);                                     \
201         }                                                                                           \
202         /**/
203 
204     #define BOOST_PROTO_BASIC_EXTENDS(Expr, Derived, Domain)                                        \
205         BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, Domain)                                           \
206         typedef void proto_is_aggregate_;                                                           \
207         /**< INTERNAL ONLY */
208 
209     #define BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, Const, Typename)                            \
210         BOOST_PROTO_DISABLE_MSVC_C4522                                                              \
211         BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                            \
212         Typename() BOOST_PROTO_RESULT_OF<                                                           \
213             Typename() This::proto_generator(                                                       \
214                 Typename() boost::proto::base_expr<                                                 \
215                     Typename() This::proto_domain                                                   \
216                   , boost::proto::tag::assign                                                       \
217                   , boost::proto::list2<                                                            \
218                         This &                                                                      \
219                       , This Const() &                                                              \
220                     >                                                                               \
221                 >::type                                                                             \
222             )                                                                                       \
223         >::type const                                                                               \
224         operator =(This Const() &a)                                                                 \
225         {                                                                                           \
226             typedef                                                                                 \
227                 Typename() boost::proto::base_expr<                                                 \
228                     Typename() This::proto_domain                                                   \
229                   , boost::proto::tag::assign                                                       \
230                   , boost::proto::list2<                                                            \
231                         This &                                                                      \
232                       , This Const() &                                                              \
233                     >                                                                               \
234                 >::type                                                                             \
235             that_type;                                                                              \
236             that_type const that = {                                                                \
237                 *this                                                                               \
238               , a                                                                                   \
239             };                                                                                      \
240             return Typename() This::proto_generator()(that);                                        \
241         }                                                                                           \
242         /**/
243 
244         // MSVC 8.0 and higher seem to need copy-assignment operator to be overloaded on *both*
245         // const and non-const rhs arguments.
246     #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) && (BOOST_MSVC > 1310)
247         #define BOOST_PROTO_EXTENDS_COPY_ASSIGN_(This, Typename)                                    \
248             BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, BOOST_PP_EMPTY, Typename)                   \
249             BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, BOOST_PROTO_CONST, Typename)                \
250             /**/
251     #else
252         #define BOOST_PROTO_EXTENDS_COPY_ASSIGN_(This, Typename)                                    \
253             BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, BOOST_PROTO_CONST, Typename)                \
254             /**/
255     #endif
256 
257         /// INTERNAL ONLY
258         ///
259     #define BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(ThisConst, ThatConst)                                  \
260         template<typename A>                                                                        \
261         BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                            \
262         typename BOOST_PROTO_RESULT_OF<                                                             \
263             proto_generator(                                                                        \
264                 typename boost::proto::base_expr<                                                   \
265                     proto_domain                                                                    \
266                   , boost::proto::tag::assign                                                       \
267                   , boost::proto::list2<                                                            \
268                         proto_derived_expr ThisConst() &                                            \
269                       , typename boost::proto::result_of::as_child<A ThatConst(), proto_domain>::type \
270                     >                                                                               \
271                 >::type                                                                             \
272             )                                                                                       \
273         >::type const                                                                               \
274         operator =(A ThatConst() &a) ThisConst()                                                    \
275         {                                                                                           \
276             typedef                                                                                 \
277                 typename boost::proto::base_expr<                                                   \
278                     proto_domain                                                                    \
279                   , boost::proto::tag::assign                                                       \
280                   , boost::proto::list2<                                                            \
281                         proto_derived_expr ThisConst() &                                            \
282                       , typename boost::proto::result_of::as_child<A ThatConst(), proto_domain>::type \
283                     >                                                                               \
284                 >::type                                                                             \
285             that_type;                                                                              \
286             that_type const that = {                                                                \
287                 *static_cast<proto_derived_expr ThisConst() *>(this)                                \
288               , boost::proto::as_child<proto_domain>(a)                                             \
289             };                                                                                      \
290             return proto_generator()(that);                                                         \
291         }                                                                                           \
292         /**/
293 
294     #define BOOST_PROTO_EXTENDS_ASSIGN_CONST_()                                                     \
295         BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PROTO_CONST, BOOST_PP_EMPTY)                         \
296         BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PROTO_CONST, BOOST_PROTO_CONST)                      \
297         /**/
298 
299     #define BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST_()                                                 \
300         BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PP_EMPTY, BOOST_PP_EMPTY)                            \
301         BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PP_EMPTY, BOOST_PROTO_CONST)                         \
302         /**/
303 
304     #define BOOST_PROTO_EXTENDS_ASSIGN_()                                                           \
305         BOOST_PROTO_EXTENDS_ASSIGN_CONST_()                                                         \
306         BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST_()                                                     \
307         /**/
308 
309     #define BOOST_PROTO_EXTENDS_ASSIGN_CONST()                                                      \
310         BOOST_PROTO_EXTENDS_COPY_ASSIGN_(proto_derived_expr, BOOST_PROTO_TYPENAME)                  \
311         BOOST_PROTO_EXTENDS_ASSIGN_CONST_()                                                         \
312         /**/
313 
314     #define BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST()                                                  \
315         BOOST_PROTO_EXTENDS_COPY_ASSIGN_(proto_derived_expr, BOOST_PROTO_TYPENAME)                  \
316         BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST_()                                                     \
317         /**/
318 
319     #define BOOST_PROTO_EXTENDS_ASSIGN()                                                            \
320         BOOST_PROTO_EXTENDS_COPY_ASSIGN_(proto_derived_expr, BOOST_PROTO_TYPENAME)                  \
321         BOOST_PROTO_EXTENDS_ASSIGN_()                                                               \
322         /**/
323 
324         /// INTERNAL ONLY
325         ///
326     #define BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(ThisConst, ThatConst)                               \
327         template<typename A>                                                                        \
328         BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                            \
329         typename BOOST_PROTO_RESULT_OF<                                                             \
330             proto_generator(                                                                        \
331                 typename boost::proto::base_expr<                                                   \
332                     proto_domain                                                                    \
333                   , boost::proto::tag::subscript                                                    \
334                   , boost::proto::list2<                                                            \
335                         proto_derived_expr ThisConst() &                                            \
336                       , typename boost::proto::result_of::as_child<A ThatConst(), proto_domain>::type \
337                     >                                                                               \
338                 >::type                                                                             \
339             )                                                                                       \
340         >::type const                                                                               \
341         operator [](A ThatConst() &a) ThisConst()                                                   \
342         {                                                                                           \
343             typedef                                                                                 \
344                 typename boost::proto::base_expr<                                                   \
345                     proto_domain                                                                    \
346                   , boost::proto::tag::subscript                                                    \
347                   , boost::proto::list2<                                                            \
348                         proto_derived_expr ThisConst() &                                            \
349                       , typename boost::proto::result_of::as_child<A ThatConst(), proto_domain>::type \
350                     >                                                                               \
351                 >::type                                                                             \
352             that_type;                                                                              \
353             that_type const that = {                                                                \
354                 *static_cast<proto_derived_expr ThisConst() *>(this)                                \
355               , boost::proto::as_child<proto_domain>(a)                                             \
356             };                                                                                      \
357             return proto_generator()(that);                                                         \
358         }                                                                                           \
359         /**/
360 
361     #define BOOST_PROTO_EXTENDS_SUBSCRIPT_CONST()                                                   \
362         BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PROTO_CONST, BOOST_PP_EMPTY)                      \
363         BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PROTO_CONST, BOOST_PROTO_CONST)                   \
364         /**/
365 
366     #define BOOST_PROTO_EXTENDS_SUBSCRIPT_NON_CONST()                                               \
367         BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PP_EMPTY, BOOST_PP_EMPTY)                         \
368         BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PP_EMPTY, BOOST_PROTO_CONST)                      \
369         /**/
370 
371     #define BOOST_PROTO_EXTENDS_SUBSCRIPT()                                                         \
372         BOOST_PROTO_EXTENDS_SUBSCRIPT_CONST()                                                       \
373         BOOST_PROTO_EXTENDS_SUBSCRIPT_NON_CONST()                                                   \
374         /**/
375 
376         /// INTERNAL ONLY
377         ///
378     #define BOOST_PROTO_EXTENDS_FUNCTION_()                                                         \
379         template<typename Sig>                                                                      \
380         struct result                                                                               \
381         {                                                                                           \
382             typedef                                                                                 \
383                 typename BOOST_PROTO_RESULT_OF<                                                     \
384                     proto_generator(                                                                \
385                         typename boost::proto::result_of::funop<                                    \
386                             Sig                                                                     \
387                           , proto_derived_expr                                                      \
388                           , proto_domain                                                            \
389                         >::type                                                                     \
390                     )                                                                               \
391                 >::type const                                                                       \
392             type;                                                                                   \
393         };                                                                                          \
394         /**/
395 
396     #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
397         #define BOOST_PROTO_EXTENDS_FUNCTION_CONST()                                                \
398             BOOST_PROTO_EXTENDS_FUNCTION_()                                                         \
399             BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PROTO_CONST)                             \
400             /**/
401 
402         #define BOOST_PROTO_EXTENDS_FUNCTION_NON_CONST()                                            \
403             BOOST_PROTO_EXTENDS_FUNCTION_()                                                         \
404             BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PP_EMPTY)                                \
405             /**/
406 
407         #define BOOST_PROTO_EXTENDS_FUNCTION()                                                      \
408             BOOST_PROTO_EXTENDS_FUNCTION_()                                                         \
409             BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PP_EMPTY)                                \
410             BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PROTO_CONST)                             \
411             /**/
412     #else
413         #define BOOST_PROTO_EXTENDS_FUNCTION_CONST()                                                \
414             BOOST_PROTO_EXTENDS_FUNCTION_()                                                         \
415             BOOST_PP_REPEAT_FROM_TO(                                                                \
416                 0                                                                                   \
417               , BOOST_PROTO_MAX_FUNCTION_CALL_ARITY                                                 \
418               , BOOST_PROTO_DEFINE_FUN_OP_CONST                                                     \
419               , ~                                                                                   \
420             )                                                                                       \
421             /**/
422 
423         #define BOOST_PROTO_EXTENDS_FUNCTION_NON_CONST()                                            \
424             BOOST_PROTO_EXTENDS_FUNCTION_()                                                         \
425             BOOST_PP_REPEAT_FROM_TO(                                                                \
426                 0                                                                                   \
427               , BOOST_PROTO_MAX_FUNCTION_CALL_ARITY                                                 \
428               , BOOST_PROTO_DEFINE_FUN_OP_NON_CONST                                                 \
429               , ~                                                                                   \
430             )                                                                                       \
431             /**/
432 
433         #define BOOST_PROTO_EXTENDS_FUNCTION()                                                      \
434             BOOST_PROTO_EXTENDS_FUNCTION_()                                                         \
435             BOOST_PP_REPEAT_FROM_TO(                                                                \
436                 0                                                                                   \
437               , BOOST_PROTO_MAX_FUNCTION_CALL_ARITY                                                 \
438               , BOOST_PROTO_DEFINE_FUN_OP                                                           \
439               , ~                                                                                   \
440             )                                                                                       \
441             /**/
442     #endif
443 
444     #define BOOST_PROTO_EXTENDS(Expr, Derived, Domain)                                              \
445         BOOST_PROTO_BASIC_EXTENDS(Expr, Derived, Domain)                                            \
446         BOOST_PROTO_EXTENDS_ASSIGN()                                                                \
447         BOOST_PROTO_EXTENDS_SUBSCRIPT()                                                             \
448         BOOST_PROTO_EXTENDS_FUNCTION()                                                              \
449         /**/
450 
451     #define BOOST_PROTO_EXTENDS_USING_ASSIGN(Derived)                                               \
452         typedef typename Derived::proto_extends proto_extends;                                      \
453         using proto_extends::operator =;                                                            \
454         BOOST_PROTO_EXTENDS_COPY_ASSIGN_(Derived, BOOST_PROTO_TYPENAME)                             \
455         /**/
456 
457     #define BOOST_PROTO_EXTENDS_USING_ASSIGN_NON_DEPENDENT(Derived)                                 \
458         typedef Derived::proto_extends proto_extends;                                               \
459         using proto_extends::operator =;                                                            \
460         BOOST_PROTO_EXTENDS_COPY_ASSIGN_(Derived, BOOST_PP_EMPTY)                                   \
461         /**/
462 
463     namespace exprns_
464     {
465         /// \brief Empty type to be used as a dummy template parameter of
466         ///     POD expression wrappers. It allows argument-dependent lookup
467         ///     to find Proto's operator overloads.
468         ///
469         /// \c proto::is_proto_expr allows argument-dependent lookup
470         ///     to find Proto's operator overloads. For example:
471         ///
472         /// \code
473         /// template<typename T, typename Dummy = proto::is_proto_expr>
474         /// struct my_terminal
475         /// {
476         ///     BOOST_PROTO_BASIC_EXTENDS(
477         ///         typename proto::terminal<T>::type
478         ///       , my_terminal<T>
479         ///       , default_domain
480         ///     )
481         /// };
482         ///
483         /// // ...
484         /// my_terminal<int> _1, _2;
485         /// _1 + _2; // OK, uses proto::operator+
486         /// \endcode
487         ///
488         /// Without the second \c Dummy template parameter, Proto's operator
489         /// overloads would not be considered by name lookup.
490         struct is_proto_expr
491         {};
492 
493         /// \brief extends\<\> class template for adding behaviors to a Proto expression template
494         ///
495         template<
496             typename Expr
497           , typename Derived
498           , typename Domain     // = proto::default_domain
499           , long Arity          // = Expr::proto_arity_c
500         >
501         struct extends
502         {
503             BOOST_FORCEINLINE
extendsboost::proto::exprns_::extends504             extends()
505               : proto_expr_()
506             {}
507 
508             BOOST_FORCEINLINE
extendsboost::proto::exprns_::extends509             extends(extends const &that)
510               : proto_expr_(that.proto_expr_)
511             {}
512 
513             BOOST_FORCEINLINE
extendsboost::proto::exprns_::extends514             extends(Expr const &expr_)
515               : proto_expr_(expr_)
516             {}
517 
518             typedef extends proto_extends;
519             BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, typename Domain)
520             BOOST_PROTO_EXTENDS_ASSIGN_CONST_()
521             BOOST_PROTO_EXTENDS_SUBSCRIPT_CONST()
522 
523             // Instead of using BOOST_PROTO_EXTENDS_FUNCTION, which uses
524             // nested preprocessor loops, use file iteration here to generate
525             // the operator() overloads, which is more efficient.
526             #include <boost/proto/detail/extends_funop_const.hpp>
527         };
528 
529         /// \brief extends\<\> class template for adding behaviors to a Proto expression template
530         ///
531         template<typename Expr, typename Derived, typename Domain>
532         struct extends<Expr, Derived, Domain, 0>
533         {
534             BOOST_FORCEINLINE
extendsboost::proto::exprns_::extends535             extends()
536               : proto_expr_()
537             {}
538 
539             BOOST_FORCEINLINE
extendsboost::proto::exprns_::extends540             extends(extends const &that)
541               : proto_expr_(that.proto_expr_)
542             {}
543 
544             BOOST_FORCEINLINE
extendsboost::proto::exprns_::extends545             extends(Expr const &expr_)
546               : proto_expr_(expr_)
547             {}
548 
549             typedef extends proto_extends;
550             BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, typename Domain)
551             BOOST_PROTO_EXTENDS_ASSIGN_()
552             BOOST_PROTO_EXTENDS_SUBSCRIPT()
553 
554             // Instead of using BOOST_PROTO_EXTENDS_FUNCTION, which uses
555             // nested preprocessor loops, use file iteration here to generate
556             // the operator() overloads, which is more efficient.
557             #include <boost/proto/detail/extends_funop.hpp>
558         };
559 
560         /// INTERNAL ONLY
561         ///
562         template<typename This, typename Fun, typename Domain>
563         struct virtual_member
564         {
565             typedef Domain proto_domain;
566             typedef typename Domain::proto_generator proto_generator;
567             typedef virtual_member<This, Fun, Domain> proto_derived_expr;
568             typedef tag::member proto_tag;
569             typedef list2<This &, expr<tag::terminal, term<Fun> > const &> proto_args;
570             typedef mpl::long_<2> proto_arity;
571             typedef detail::not_a_valid_type proto_address_of_hack_type_;
572             typedef void proto_is_expr_; /**< INTERNAL ONLY */
573             static const long proto_arity_c = 2;
574             typedef boost::proto::tag::proto_expr<proto_tag, Domain> fusion_tag;
575             typedef This &proto_child0;
576             typedef expr<tag::terminal, term<Fun> > const &proto_child1;
577             typedef expr<proto_tag, proto_args, proto_arity_c> proto_base_expr;
578             typedef basic_expr<proto_tag, proto_args, proto_arity_c> proto_grammar;
579             typedef void proto_is_aggregate_; /**< INTERNAL ONLY */
580 
581             BOOST_PROTO_EXTENDS_ASSIGN_()
BOOST_PROTO_EXTENDS_SUBSCRIPTboost::proto::exprns_::virtual_member582             BOOST_PROTO_EXTENDS_SUBSCRIPT()
583 
584             // Instead of using BOOST_PROTO_EXTENDS_FUNCTION, which uses
585             // nested preprocessor loops, use file iteration here to generate
586             // the operator() overloads, which is more efficient.
587             #define BOOST_PROTO_NO_WAVE_OUTPUT
588             #include <boost/proto/detail/extends_funop.hpp>
589             #undef BOOST_PROTO_NO_WAVE_OUTPUT
590 
591             BOOST_FORCEINLINE
592             proto_base_expr const proto_base() const
593             {
594                 proto_base_expr that = {this->child0(), this->child1()};
595                 return that;
596             }
597 
598             BOOST_FORCEINLINE
child0boost::proto::exprns_::virtual_member599             proto_child0 child0() const
600             {
601                 using std::size_t;
602                 return *(This *)((char *)this - BOOST_PROTO_OFFSETOF(This, proto_member_union_start_));
603             }
604 
605             BOOST_FORCEINLINE
child1boost::proto::exprns_::virtual_member606             proto_child1 child1() const
607             {
608                 static expr<tag::terminal, term<Fun>, 0> const that = {Fun()};
609                 return that;
610             }
611         };
612 
613         /// INTERNAL ONLY
614         ///
615         #define BOOST_PROTO_EXTENDS_MEMBER_(R, DOMAIN, ELEM)                                            \
616             boost::proto::exprns_::virtual_member<                                                      \
617                 proto_derived_expr                                                                      \
618               , BOOST_PP_TUPLE_ELEM(2, 0, ELEM)                                                         \
619               , DOMAIN                                                                                  \
620             > BOOST_PP_TUPLE_ELEM(2, 1, ELEM);                                                          \
621             /**/
622 
623         /// \brief For declaring virtual data members in an extension class.
624         ///
625         #define BOOST_PROTO_EXTENDS_MEMBERS_WITH_DOMAIN(SEQ, DOMAIN)                                    \
626             union                                                                                       \
627             {                                                                                           \
628                 char proto_member_union_start_;                                                         \
629                 BOOST_PP_SEQ_FOR_EACH(BOOST_PROTO_EXTENDS_MEMBER_, DOMAIN, SEQ)                         \
630             };                                                                                          \
631             /**/
632 
633         /// \brief For declaring virtual data members in an extension class.
634         ///
635         #define BOOST_PROTO_EXTENDS_MEMBERS(SEQ)                                                        \
636             BOOST_PROTO_EXTENDS_MEMBERS_WITH_DOMAIN(SEQ, proto_domain)                                  \
637             /**/
638 
639     }
640 
641 }}
642 
643 #if defined(_MSC_VER)
644 # pragma warning(pop)
645 #endif
646 
647 #endif
648