1 ///////////////////////////////////////////////////////////////////////////////
3 /// Macros and a base class for defining end-user expression types
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
40 # define BOOST_PROTO_ADDROF(x) ((char const volatile*)boost::addressof(x))
43 # define BOOST_PROTO_OFFSETOF(s,m) (BOOST_PROTO_ADDROF((((s *)this)->m)) - BOOST_PROTO_ADDROF(*((s *)this)))
47 # define BOOST_PROTO_OFFSETOF offsetof
52 #define BOOST_PROTO_CONST0
56 #define BOOST_PROTO_CONST1 const
60 #define BOOST_PROTO_TEMPLATE_YES_(Z, N) template<BOOST_PP_ENUM_PARAMS_Z(Z, N, typename A)>
64 #define BOOST_PROTO_TEMPLATE_NO_(Z, N)
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< \
72 typename boost::proto::result_of::BOOST_PP_CAT(funop, N)< \
73 proto_derived_expr BOOST_PROTO_CONST ## Const \
75 BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, const A) \
79 operator ()(BOOST_PP_ENUM_BINARY_PARAMS_Z(Z, N, A, const &a)) BOOST_PROTO_CONST ## Const \
81 typedef boost::proto::result_of::BOOST_PP_CAT(funop, N)< \
82 proto_derived_expr BOOST_PROTO_CONST ## Const \
84 BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, const A) \
86 return proto_domain()( \
88 *static_cast<proto_derived_expr BOOST_PROTO_CONST ## Const *>(this) \
89 BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, a) \
97 #define BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(Const) \
98 template<typename... A> \
99 typename boost::result_of< \
101 typename boost::proto::result_of::funop< \
102 proto_derived_expr BOOST_PROTO_CONST ## Const(A const &...) \
103 , proto_derived_expr \
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 \
115 return proto_domain()( \
117 *static_cast<proto_derived_expr BOOST_PROTO_CONST ## Const *>(this) \
126 #define BOOST_PROTO_DEFINE_FUN_OP_CONST(Z, N, DATA) \
127 BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, 1)
131 #define BOOST_PROTO_DEFINE_FUN_OP_NON_CONST(Z, N, DATA) \
132 BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, 0)
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) \
143 #define BOOST_PROTO_EXTENDS_CHILD(Z, N, DATA) \
145 typename proto_base_expr::BOOST_PP_CAT(proto_child, N) \
146 BOOST_PP_CAT(proto_child, N); \
149 #define BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, Domain) \
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}; \
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); \
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 */
193 #define BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(Const) \
194 template<typename A> \
195 typename boost::result_of< \
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 \
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 \
216 *static_cast<proto_derived_expr BOOST_PROTO_CONST ## Const *>(this) \
217 , boost::proto::as_child<proto_domain>(a) \
219 return proto_domain()(that); \
222 template<typename A> \
223 typename boost::result_of< \
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 \
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 \
244 *static_cast<proto_derived_expr BOOST_PROTO_CONST ## Const *>(this) \
245 , boost::proto::as_child<proto_domain>(a) \
247 return proto_domain()(that); \
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() \
264 #define BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(Const) \
265 template<typename A> \
266 typename boost::result_of< \
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 \
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 \
287 *static_cast<proto_derived_expr BOOST_PROTO_CONST ## Const *>(this) \
288 , boost::proto::as_child<proto_domain>(a) \
290 return proto_domain()(that); \
293 template<typename A> \
294 typename boost::result_of< \
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 \
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 \
315 *static_cast<proto_derived_expr BOOST_PROTO_CONST ## Const *>(this) \
316 , boost::proto::as_child<proto_domain>(a) \
318 return proto_domain()(that); \
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() \
335 #define BOOST_PROTO_EXTENDS_FUNCTION_() \
336 template<typename Sig> \
340 typename boost::result_of< \
342 typename boost::proto::result_of::funop< \
344 , proto_derived_expr \
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) \
359 #define BOOST_PROTO_EXTENDS_FUNCTION_NON_CONST() \
360 BOOST_PROTO_EXTENDS_FUNCTION_() \
361 BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(0) \
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) \
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 \
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 \
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 \
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() \
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:
418 /// template<typename T, typename Dummy = proto::is_proto_expr>
419 /// struct my_terminal
421 /// BOOST_PROTO_BASIC_EXTENDS(
422 /// typename proto::terminal<T>::type
429 /// my_terminal<int> _1, _2;
430 /// _1 + _2; // OK, uses proto::operator+
433 /// Without the second \c Dummy template parameter, Proto's operator
434 /// overloads would not be considered by name lookup.
438 /// \brief extends\<\> class template for adding behaviors to a Proto expression template
443 , typename Domain
BOOST_PROTO_WHEN_BUILDING_DOCS(= proto::default_domain
)
444 , long Arity
BOOST_PROTO_WHEN_BUILDING_DOCS(= Expr::proto_arity_c
)
452 extends(extends
const &that
)
453 : proto_expr_(that
.proto_expr_
)
456 extends(Expr
const &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)
474 #define BOOST_PP_LOCAL_MACRO(N) \
475 BOOST_PROTO_DEFINE_FUN_OP_CONST(1, N, ~) \
480 #define BOOST_PP_LOCAL_LIMITS (0, BOOST_PP_DEC(BOOST_PROTO_MAX_FUNCTION_CALL_ARITY))
481 #include BOOST_PP_LOCAL_ITERATE()
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>
495 extends(extends
const &that
)
496 : proto_expr_(that
.proto_expr_
)
499 extends(Expr
const &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)
519 #define BOOST_PP_LOCAL_MACRO(N) \
520 BOOST_PROTO_DEFINE_FUN_OP(1, N, ~) \
525 #define BOOST_PP_LOCAL_LIMITS (0, BOOST_PP_DEC(BOOST_PROTO_MAX_FUNCTION_CALL_ARITY))
526 #include BOOST_PP_LOCAL_ITERATE()
533 template<typename This
, typename Fun
, typename Domain
>
534 struct virtual_member
537 expr
<tag::member
, list2
<This
&, expr
<tag::terminal
, term
<Fun
> > const &> >
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()};
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()};
574 #define BOOST_PROTO_EXTENDS_MEMBER_(R, DATA, ELEM) \
575 boost::proto::exprns_::virtual_member< \
577 , BOOST_PP_TUPLE_ELEM(2, 0, ELEM) \
579 > BOOST_PP_TUPLE_ELEM(2, 1, ELEM); \
582 /// \brief For declaring virtual data members in an extension class.
584 #define BOOST_PROTO_EXTENDS_MEMBERS(SEQ) \
587 char proto_member_union_start_; \
588 BOOST_PP_SEQ_FOR_EACH(BOOST_PROTO_EXTENDS_MEMBER_, ~, SEQ) \
592 BOOST_PROTO_END_ADL_NAMESPACE(exprns_
)