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