fix doc example typo
[boost.git] / boost / proto / extends.hpp
blobc9354f9360cf2aeca38ce9fd24a101160457e2fa
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)
9 #ifndef BOOST_PROTO_EXTENDS_HPP_EAN_11_1_2006
10 #define BOOST_PROTO_EXTENDS_HPP_EAN_11_1_2006
12 #include <boost/proto/detail/prefix.hpp>
13 #include <cstddef> // for offsetof
14 #include <boost/preprocessor/tuple/elem.hpp>
15 #include <boost/preprocessor/control/if.hpp>
16 #include <boost/preprocessor/arithmetic/inc.hpp>
17 #include <boost/preprocessor/arithmetic/dec.hpp>
18 #include <boost/preprocessor/iteration/local.hpp>
19 #include <boost/preprocessor/repetition/enum_params.hpp>
20 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
21 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
22 #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
23 #include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp>
24 #include <boost/preprocessor/seq/for_each.hpp>
25 #include <boost/utility/addressof.hpp>
26 #include <boost/utility/result_of.hpp>
27 #include <boost/proto/proto_fwd.hpp>
28 #include <boost/proto/traits.hpp>
29 #include <boost/proto/expr.hpp>
30 #include <boost/proto/args.hpp>
31 #include <boost/proto/traits.hpp>
32 #include <boost/proto/generate.hpp>
33 #include <boost/proto/detail/suffix.hpp>
35 namespace boost { namespace proto
37 #ifdef __GNUC__
38 /// INTERNAL ONLY
39 ///
40 # define BOOST_PROTO_ADDROF(x) ((char const volatile*)boost::addressof(x))
41 /// INTERNAL ONLY
42 ///
43 # define BOOST_PROTO_OFFSETOF(s,m) (BOOST_PROTO_ADDROF((((s *)this)->m)) - BOOST_PROTO_ADDROF(*((s *)this)))
44 #else
45 /// INTERNAL ONLY
46 ///
47 # define BOOST_PROTO_OFFSETOF offsetof
48 #endif
50 /// INTERNAL ONLY
51 ///
52 #define BOOST_PROTO_CONST0
54 /// INTERNAL ONLY
55 ///
56 #define BOOST_PROTO_CONST1 const
58 /// INTERNAL ONLY
59 ///
60 #define BOOST_PROTO_TEMPLATE_YES_(Z, N) template<BOOST_PP_ENUM_PARAMS_Z(Z, N, typename A)>
62 /// INTERNAL ONLY
63 ///
64 #define BOOST_PROTO_TEMPLATE_NO_(Z, N)
66 /// INTERNAL ONLY
67 ///
68 #define BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, Const) \
69 BOOST_PP_IF(N, BOOST_PROTO_TEMPLATE_YES_, BOOST_PROTO_TEMPLATE_NO_)(Z, N) \
70 typename boost::result_of< \
71 proto_domain( \
72 typename boost::proto::result_of::BOOST_PP_CAT(funop, N)< \
73 proto_derived_expr BOOST_PROTO_CONST ## Const \
74 , proto_domain \
75 BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, const A) \
76 >::type \
77 ) \
78 >::type const \
79 operator ()(BOOST_PP_ENUM_BINARY_PARAMS_Z(Z, N, A, const &a)) BOOST_PROTO_CONST ## Const \
80 { \
81 typedef boost::proto::result_of::BOOST_PP_CAT(funop, N)< \
82 proto_derived_expr BOOST_PROTO_CONST ## Const \
83 , proto_domain \
84 BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, const A) \
85 > funop; \
86 return proto_domain()( \
87 funop::call( \
88 *static_cast<proto_derived_expr BOOST_PROTO_CONST ## Const *>(this) \
89 BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, a) \
90 ) \
91 ); \
92 } \
93 /**/
95 /// INTERNAL ONLY
96 ///
97 #define BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(Const) \
98 template<typename... A> \
99 typename boost::result_of< \
100 proto_domain( \
101 typename boost::proto::result_of::funop< \
102 proto_derived_expr BOOST_PROTO_CONST ## Const(A const &...) \
103 , proto_derived_expr \
104 , proto_domain \
105 >::type \
107 >::type const \
108 operator ()(A const &...a) BOOST_PROTO_CONST ## Const \
110 typedef boost::proto::result_of::funop< \
111 proto_derived_expr BOOST_PROTO_CONST ## Const(A const &...) \
112 , proto_derived_expr \
113 , proto_domain \
114 > funop; \
115 return proto_domain()( \
116 funop::call( \
117 *static_cast<proto_derived_expr BOOST_PROTO_CONST ## Const *>(this) \
118 , a... \
120 ); \
122 /**/
124 /// INTERNAL ONLY
126 #define BOOST_PROTO_DEFINE_FUN_OP_CONST(Z, N, DATA) \
127 BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, 1)
129 /// INTERNAL ONLY
131 #define BOOST_PROTO_DEFINE_FUN_OP_NON_CONST(Z, N, DATA) \
132 BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, 0)
134 /// INTERNAL ONLY
136 #define BOOST_PROTO_DEFINE_FUN_OP(Z, N, DATA) \
137 BOOST_PROTO_DEFINE_FUN_OP_CONST(Z, N, DATA) \
138 BOOST_PROTO_DEFINE_FUN_OP_NON_CONST(Z, N, DATA) \
139 /**/
141 /// INTERNAL ONLY
143 #define BOOST_PROTO_EXTENDS_CHILD(Z, N, DATA) \
144 typedef \
145 typename proto_base_expr::BOOST_PP_CAT(proto_child, N) \
146 BOOST_PP_CAT(proto_child, N); \
147 /**/
149 #define BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, Domain) \
150 Expr proto_expr_; \
152 typedef typename Expr::proto_base_expr proto_base_expr; \
153 typedef Domain proto_domain; \
154 typedef Derived proto_derived_expr; \
155 typedef typename proto_base_expr::proto_tag proto_tag; \
156 typedef typename proto_base_expr::proto_args proto_args; \
157 typedef typename proto_base_expr::proto_arity proto_arity; \
158 typedef typename proto_base_expr::address_of_hack_type_ proto_address_of_hack_type_; \
159 typedef void proto_is_expr_; /**< INTERNAL ONLY */ \
160 BOOST_STATIC_CONSTANT(long, proto_arity_c = proto_base_expr::proto_arity_c); \
161 BOOST_PROTO_FUSION_DEFINE_TAG(boost::proto::tag::proto_expr) \
162 BOOST_PP_REPEAT(BOOST_PROTO_MAX_ARITY, BOOST_PROTO_EXTENDS_CHILD, ~) \
164 static proto_derived_expr const make(Expr const &expr) \
166 proto_derived_expr that = {expr}; \
167 return that; \
170 proto_base_expr &proto_base() \
172 return this->proto_expr_.proto_base(); \
175 proto_base_expr const &proto_base() const \
177 return this->proto_expr_.proto_base(); \
180 operator proto_address_of_hack_type_() const \
182 return boost::addressof(this->proto_base().child0); \
184 /**/
186 #define BOOST_PROTO_BASIC_EXTENDS(Expr, Derived, Domain) \
187 BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, Domain) \
188 typedef void proto_is_aggregate_; \
189 /**< INTERNAL ONLY */
191 /// INTERNAL ONLY
193 #define BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(Const) \
194 template<typename A> \
195 typename boost::result_of< \
196 proto_domain( \
197 boost::proto::expr< \
198 boost::proto::tag::assign \
199 , boost::proto::list2< \
200 proto_derived_expr BOOST_PROTO_CONST ## Const & \
201 , typename boost::proto::result_of::as_child<A, proto_domain>::type \
205 >::type const \
206 operator =(A &a) BOOST_PROTO_CONST ## Const \
208 typedef boost::proto::expr< \
209 boost::proto::tag::assign \
210 , boost::proto::list2< \
211 proto_derived_expr BOOST_PROTO_CONST ## Const & \
212 , typename boost::proto::result_of::as_child<A, proto_domain>::type \
214 > that_type; \
215 that_type that = { \
216 *static_cast<proto_derived_expr BOOST_PROTO_CONST ## Const *>(this) \
217 , boost::proto::as_child<proto_domain>(a) \
218 }; \
219 return proto_domain()(that); \
222 template<typename A> \
223 typename boost::result_of< \
224 proto_domain( \
225 boost::proto::expr< \
226 boost::proto::tag::assign \
227 , boost::proto::list2< \
228 proto_derived_expr BOOST_PROTO_CONST ## Const & \
229 , typename boost::proto::result_of::as_child<A const, proto_domain>::type \
233 >::type const \
234 operator =(A const &a) BOOST_PROTO_CONST ## Const \
236 typedef boost::proto::expr< \
237 boost::proto::tag::assign \
238 , boost::proto::list2< \
239 proto_derived_expr BOOST_PROTO_CONST ## Const & \
240 , typename boost::proto::result_of::as_child<A const, proto_domain>::type \
242 > that_type; \
243 that_type that = { \
244 *static_cast<proto_derived_expr BOOST_PROTO_CONST ## Const *>(this) \
245 , boost::proto::as_child<proto_domain>(a) \
246 }; \
247 return proto_domain()(that); \
249 /**/
251 #define BOOST_PROTO_EXTENDS_ASSIGN_CONST() \
252 BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(1)
254 #define BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST() \
255 BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(0)
257 #define BOOST_PROTO_EXTENDS_ASSIGN() \
258 BOOST_PROTO_EXTENDS_ASSIGN_CONST() \
259 BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST() \
260 /**/
262 /// INTERNAL ONLY
264 #define BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(Const) \
265 template<typename A> \
266 typename boost::result_of< \
267 proto_domain( \
268 boost::proto::expr< \
269 boost::proto::tag::subscript \
270 , boost::proto::list2< \
271 proto_derived_expr BOOST_PROTO_CONST ## Const & \
272 , typename boost::proto::result_of::as_child<A, proto_domain>::type \
276 >::type const \
277 operator [](A &a) BOOST_PROTO_CONST ## Const \
279 typedef boost::proto::expr< \
280 boost::proto::tag::subscript \
281 , boost::proto::list2< \
282 proto_derived_expr BOOST_PROTO_CONST ## Const & \
283 , typename boost::proto::result_of::as_child<A, proto_domain>::type \
285 > that_type; \
286 that_type that = { \
287 *static_cast<proto_derived_expr BOOST_PROTO_CONST ## Const *>(this) \
288 , boost::proto::as_child<proto_domain>(a) \
289 }; \
290 return proto_domain()(that); \
293 template<typename A> \
294 typename boost::result_of< \
295 proto_domain( \
296 boost::proto::expr< \
297 boost::proto::tag::subscript \
298 , boost::proto::list2< \
299 proto_derived_expr BOOST_PROTO_CONST ## Const & \
300 , typename boost::proto::result_of::as_child<A const, proto_domain>::type \
304 >::type const \
305 operator [](A const &a) BOOST_PROTO_CONST ## Const \
307 typedef boost::proto::expr< \
308 boost::proto::tag::subscript \
309 , boost::proto::list2< \
310 proto_derived_expr BOOST_PROTO_CONST ## Const & \
311 , typename boost::proto::result_of::as_child<A const, proto_domain>::type \
313 > that_type; \
314 that_type that = { \
315 *static_cast<proto_derived_expr BOOST_PROTO_CONST ## Const *>(this) \
316 , boost::proto::as_child<proto_domain>(a) \
317 }; \
318 return proto_domain()(that); \
320 /**/
322 #define BOOST_PROTO_EXTENDS_SUBSCRIPT_CONST() \
323 BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(1)
325 #define BOOST_PROTO_EXTENDS_SUBSCRIPT_NON_CONST() \
326 BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(0)
328 #define BOOST_PROTO_EXTENDS_SUBSCRIPT() \
329 BOOST_PROTO_EXTENDS_SUBSCRIPT_CONST() \
330 BOOST_PROTO_EXTENDS_SUBSCRIPT_NON_CONST() \
331 /**/
333 /// INTERNAL ONLY
335 #define BOOST_PROTO_EXTENDS_FUNCTION_() \
336 template<typename Sig> \
337 struct result \
339 typedef \
340 typename boost::result_of< \
341 proto_domain( \
342 typename boost::proto::result_of::funop< \
343 Sig \
344 , proto_derived_expr \
345 , proto_domain \
346 >::type \
348 >::type const \
349 type; \
350 }; \
351 /**/
353 #ifdef BOOST_HAS_VARIADIC_TMPL
354 #define BOOST_PROTO_EXTENDS_FUNCTION_CONST() \
355 BOOST_PROTO_EXTENDS_FUNCTION_() \
356 BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(1) \
357 /**/
359 #define BOOST_PROTO_EXTENDS_FUNCTION_NON_CONST() \
360 BOOST_PROTO_EXTENDS_FUNCTION_() \
361 BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(0) \
362 /**/
364 #define BOOST_PROTO_EXTENDS_FUNCTION() \
365 BOOST_PROTO_EXTENDS_FUNCTION_() \
366 BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(0) \
367 BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(1) \
368 /**/
369 #else
370 #define BOOST_PROTO_EXTENDS_FUNCTION_CONST() \
371 BOOST_PROTO_EXTENDS_FUNCTION_() \
372 BOOST_PP_REPEAT_FROM_TO( \
374 , BOOST_PROTO_MAX_FUNCTION_CALL_ARITY \
375 , BOOST_PROTO_DEFINE_FUN_OP_CONST \
376 , ~ \
378 /**/
380 #define BOOST_PROTO_EXTENDS_FUNCTION_NON_CONST() \
381 BOOST_PROTO_EXTENDS_FUNCTION_() \
382 BOOST_PP_REPEAT_FROM_TO( \
384 , BOOST_PROTO_MAX_FUNCTION_CALL_ARITY \
385 , BOOST_PROTO_DEFINE_FUN_OP_NON_CONST \
386 , ~ \
388 /**/
390 #define BOOST_PROTO_EXTENDS_FUNCTION() \
391 BOOST_PROTO_EXTENDS_FUNCTION_() \
392 BOOST_PP_REPEAT_FROM_TO( \
394 , BOOST_PROTO_MAX_FUNCTION_CALL_ARITY \
395 , BOOST_PROTO_DEFINE_FUN_OP \
396 , ~ \
398 /**/
399 #endif
401 #define BOOST_PROTO_EXTENDS(Expr, Derived, Domain) \
402 BOOST_PROTO_BASIC_EXTENDS(Expr, Derived, Domain) \
403 BOOST_PROTO_EXTENDS_ASSIGN() \
404 BOOST_PROTO_EXTENDS_SUBSCRIPT() \
405 BOOST_PROTO_EXTENDS_FUNCTION() \
406 /**/
408 BOOST_PROTO_BEGIN_ADL_NAMESPACE(exprns_)
410 /// \brief Empty type to be used as a dummy template parameter of
411 /// POD expression wrappers. It allows argument-dependent lookup
412 /// to find Proto's operator overloads.
414 /// \c proto::is_proto_expr allows argument-dependent lookup
415 /// to find Proto's operator overloads. For example:
417 /// \code
418 /// template<typename T, typename Dummy = proto::is_proto_expr>
419 /// struct my_terminal
420 /// {
421 /// BOOST_PROTO_BASIC_EXTENDS(
422 /// typename proto::terminal<T>::type
423 /// , my_terminal<T>
424 /// , default_domain
425 /// )
426 /// };
428 /// // ...
429 /// my_terminal<int> _1, _2;
430 /// _1 + _2; // OK, uses proto::operator+
431 /// \endcode
433 /// Without the second \c Dummy template parameter, Proto's operator
434 /// overloads would not be considered by name lookup.
435 struct is_proto_expr
438 /// \brief extends\<\> class template for adding behaviors to a Proto expression template
440 template<
441 typename Expr
442 , typename Derived
443 , typename Domain BOOST_PROTO_WHEN_BUILDING_DOCS(= proto::default_domain)
444 , long Arity BOOST_PROTO_WHEN_BUILDING_DOCS(= Expr::proto_arity_c)
446 struct extends
448 extends()
449 : proto_expr_()
452 extends(extends const &that)
453 : proto_expr_(that.proto_expr_)
456 extends(Expr const &expr_)
457 : proto_expr_(expr_)
460 BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, Domain)
461 BOOST_PROTO_EXTENDS_ASSIGN_CONST()
462 BOOST_PROTO_EXTENDS_SUBSCRIPT_CONST()
464 // Instead of using BOOST_PROTO_EXTENDS_FUNCTION, which uses
465 // nested preprocessor loops, use file iteration here to generate
466 // the operator() overloads, which is more efficient.
467 BOOST_PROTO_EXTENDS_FUNCTION_()
469 #ifdef BOOST_HAS_VARIADIC_TMPL
470 BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(1)
471 #else
472 /// INTERNAL ONLY
474 #define BOOST_PP_LOCAL_MACRO(N) \
475 BOOST_PROTO_DEFINE_FUN_OP_CONST(1, N, ~) \
476 /**/
478 /// INTERNAL ONLY
480 #define BOOST_PP_LOCAL_LIMITS (0, BOOST_PP_DEC(BOOST_PROTO_MAX_FUNCTION_CALL_ARITY))
481 #include BOOST_PP_LOCAL_ITERATE()
483 #endif
486 /// \brief extends\<\> class template for adding behaviors to a Proto expression template
488 template<typename Expr, typename Derived, typename Domain>
489 struct extends<Expr, Derived, Domain, 0>
491 extends()
492 : proto_expr_()
495 extends(extends const &that)
496 : proto_expr_(that.proto_expr_)
499 extends(Expr const &expr_)
500 : proto_expr_(expr_)
503 BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, Domain)
504 BOOST_PROTO_EXTENDS_ASSIGN()
505 BOOST_PROTO_EXTENDS_SUBSCRIPT()
507 // Instead of using BOOST_PROTO_EXTENDS_FUNCTION, which uses
508 // nested preprocessor loops, use file iteration here to generate
509 // the operator() overloads, which is more efficient.
510 BOOST_PROTO_EXTENDS_FUNCTION_()
512 #ifdef BOOST_HAS_VARIADIC_TMPL
513 BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(0)
514 BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(1)
515 #else
517 /// INTERNAL ONLY
519 #define BOOST_PP_LOCAL_MACRO(N) \
520 BOOST_PROTO_DEFINE_FUN_OP(1, N, ~) \
521 /**/
523 /// INTERNAL ONLY
525 #define BOOST_PP_LOCAL_LIMITS (0, BOOST_PP_DEC(BOOST_PROTO_MAX_FUNCTION_CALL_ARITY))
526 #include BOOST_PP_LOCAL_ITERATE()
528 #endif
531 /// INTERNAL ONLY
533 template<typename This, typename Fun, typename Domain>
534 struct virtual_member
536 typedef
537 expr<tag::member, list2<This &, expr<tag::terminal, term<Fun> > const &> >
538 proto_base_expr;
539 typedef Domain proto_domain;
540 typedef virtual_member<This, Fun, Domain> proto_derived_expr;
541 typedef typename proto_base_expr::proto_tag proto_tag;
542 typedef typename proto_base_expr::proto_args proto_args;
543 typedef typename proto_base_expr::proto_arity proto_arity;
544 typedef typename proto_base_expr::address_of_hack_type_ proto_address_of_hack_type_;
545 typedef void proto_is_expr_; /**< INTERNAL ONLY */
546 BOOST_PROTO_FUSION_DEFINE_TAG(boost::proto::tag::proto_expr)
547 BOOST_PP_REPEAT(BOOST_PROTO_MAX_ARITY, BOOST_PROTO_EXTENDS_CHILD, ~)
548 typedef void proto_is_aggregate_; /**< INTERNAL ONLY */
550 BOOST_PROTO_EXTENDS_ASSIGN()
551 BOOST_PROTO_EXTENDS_SUBSCRIPT()
552 BOOST_PROTO_EXTENDS_FUNCTION()
554 proto_base_expr const proto_base() const
556 proto_base_expr that = {this->child0(), this->child1()};
557 return that;
560 proto_child0 child0() const
562 return *(This *)((char *)this - BOOST_PROTO_OFFSETOF(This, proto_member_union_start_));
565 proto_child1 child1() const
567 static expr<tag::terminal, term<Fun> > const that = {Fun()};
568 return that;
572 /// INTERNAL ONLY
574 #define BOOST_PROTO_EXTENDS_MEMBER_(R, DATA, ELEM) \
575 boost::proto::exprns_::virtual_member< \
576 proto_derived_expr \
577 , BOOST_PP_TUPLE_ELEM(2, 0, ELEM) \
578 , proto_domain \
579 > BOOST_PP_TUPLE_ELEM(2, 1, ELEM); \
580 /**/
582 /// \brief For declaring virtual data members in an extension class.
584 #define BOOST_PROTO_EXTENDS_MEMBERS(SEQ) \
585 union \
587 char proto_member_union_start_; \
588 BOOST_PP_SEQ_FOR_EACH(BOOST_PROTO_EXTENDS_MEMBER_, ~, SEQ) \
589 }; \
590 /**/
592 BOOST_PROTO_END_ADL_NAMESPACE(exprns_)
596 #endif