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 <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>
38
#define BOOST_PROTO_DISABLE_MSVC_C4522 __pragma(warning(disable: 4522))
40
#define BOOST_PROTO_DISABLE_MSVC_C4522
43
namespace boost { namespace proto
48
# define BOOST_PROTO_ADDROF(x) ((char const volatile*)boost::addressof(x))
51
# define BOOST_PROTO_OFFSETOF(s,m) (BOOST_PROTO_ADDROF((((s *)this)->m)) - BOOST_PROTO_ADDROF(*((s *)this)))
55
# define BOOST_PROTO_OFFSETOF offsetof
60
#define BOOST_PROTO_CONST() const
64
#define BOOST_PROTO_TYPENAME() typename
68
#define BOOST_PROTO_TEMPLATE_YES_(Z, N) template<BOOST_PP_ENUM_PARAMS_Z(Z, N, typename A)>
72
#define BOOST_PROTO_TEMPLATE_NO_(Z, N)
76
#define BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, Const) \
77
BOOST_PP_IF(N, BOOST_PROTO_TEMPLATE_YES_, BOOST_PROTO_TEMPLATE_NO_)(Z, N) \
79
typename BOOST_PROTO_RESULT_OF< \
81
typename boost::proto::result_of::BOOST_PP_CAT(funop, N)< \
82
proto_derived_expr Const() \
84
BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, const A) \
88
operator ()(BOOST_PP_ENUM_BINARY_PARAMS_Z(Z, N, A, const &a)) Const() \
90
typedef boost::proto::result_of::BOOST_PP_CAT(funop, N)< \
91
proto_derived_expr Const() \
93
BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, const A) \
95
return proto_generator()( \
97
*static_cast<proto_derived_expr Const() *>(this) \
98
BOOST_PP_ENUM_TRAILING_PARAMS_Z(Z, N, a) \
106
#define BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(Const) \
107
template<typename... A> \
109
typename BOOST_PROTO_RESULT_OF< \
111
typename boost::proto::result_of::funop< \
112
proto_derived_expr Const()(A const &...) \
113
, proto_derived_expr \
118
operator ()(A const &...a) Const() \
120
typedef boost::proto::result_of::funop< \
121
proto_derived_expr Const()(A const &...) \
122
, proto_derived_expr \
125
return proto_generator()( \
127
*static_cast<proto_derived_expr Const() *>(this) \
136
#define BOOST_PROTO_DEFINE_FUN_OP_CONST(Z, N, DATA) \
137
BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, BOOST_PROTO_CONST) \
142
#define BOOST_PROTO_DEFINE_FUN_OP_NON_CONST(Z, N, DATA) \
143
BOOST_PROTO_DEFINE_FUN_OP_IMPL_(Z, N, DATA, BOOST_PP_EMPTY) \
148
#define BOOST_PROTO_DEFINE_FUN_OP(Z, N, DATA) \
149
BOOST_PROTO_DEFINE_FUN_OP_CONST(Z, N, DATA) \
150
BOOST_PROTO_DEFINE_FUN_OP_NON_CONST(Z, N, DATA) \
155
#define BOOST_PROTO_EXTENDS_CHILD(Z, N, DATA) \
157
typename proto_base_expr::BOOST_PP_CAT(proto_child, N) \
158
BOOST_PP_CAT(proto_child, N); \
161
#define BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, Domain) \
164
typedef Expr proto_base_expr_; /**< INTERNAL ONLY */ \
165
typedef typename proto_base_expr_::proto_base_expr proto_base_expr; \
166
typedef BOOST_PROTO_REMOVE_TYPENAME(Domain) proto_domain; \
167
typedef Derived proto_derived_expr; \
168
typedef Domain::proto_generator proto_generator; \
169
typedef typename proto_base_expr::proto_tag proto_tag; \
170
typedef typename proto_base_expr::proto_args proto_args; \
171
typedef typename proto_base_expr::proto_arity proto_arity; \
172
typedef typename proto_base_expr::proto_grammar proto_grammar; \
173
typedef typename proto_base_expr::address_of_hack_type_ proto_address_of_hack_type_; \
174
typedef void proto_is_expr_; /**< INTERNAL ONLY */ \
175
static const long proto_arity_c = proto_base_expr::proto_arity_c; \
176
typedef boost::proto::tag::proto_expr fusion_tag; \
177
BOOST_PP_REPEAT(BOOST_PROTO_MAX_ARITY, BOOST_PROTO_EXTENDS_CHILD, ~) \
180
static proto_derived_expr const make(Expr const &e) \
182
proto_derived_expr that = {e}; \
187
proto_base_expr &proto_base() \
189
return this->proto_expr_.proto_base(); \
193
proto_base_expr const &proto_base() const \
195
return this->proto_expr_.proto_base(); \
199
operator proto_address_of_hack_type_() const \
201
return boost::addressof(this->proto_base().child0); \
205
#define BOOST_PROTO_BASIC_EXTENDS(Expr, Derived, Domain) \
206
BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, Domain) \
207
typedef void proto_is_aggregate_; \
208
/**< INTERNAL ONLY */
210
#define BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, Const, Typename) \
211
BOOST_PROTO_DISABLE_MSVC_C4522 \
213
Typename() BOOST_PROTO_RESULT_OF< \
214
Typename() This::proto_generator( \
215
Typename() boost::proto::base_expr< \
216
Typename() This::proto_domain \
217
, boost::proto::tag::assign \
218
, boost::proto::list2< \
225
operator =(This Const() &a) \
228
Typename() boost::proto::base_expr< \
229
Typename() This::proto_domain \
230
, boost::proto::tag::assign \
231
, boost::proto::list2< \
237
that_type const that = { \
241
return Typename() This::proto_generator()(that); \
245
// MSVC 8.0 and higher seem to need copy-assignment operator to be overloaded on *both*
246
// const and non-const rhs arguments.
247
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) && (BOOST_MSVC > 1310)
248
#define BOOST_PROTO_EXTENDS_COPY_ASSIGN_(This, Typename) \
249
BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, BOOST_PP_EMPTY, Typename) \
250
BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, BOOST_PROTO_CONST, Typename) \
253
#define BOOST_PROTO_EXTENDS_COPY_ASSIGN_(This, Typename) \
254
BOOST_PROTO_EXTENDS_COPY_ASSIGN_IMPL_(This, BOOST_PROTO_CONST, Typename) \
260
#define BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(ThisConst, ThatConst) \
261
template<typename A> \
263
typename BOOST_PROTO_RESULT_OF< \
265
typename boost::proto::base_expr< \
267
, boost::proto::tag::assign \
268
, boost::proto::list2< \
269
proto_derived_expr ThisConst() & \
270
, typename boost::proto::result_of::as_child<A ThatConst(), proto_domain>::type \
275
operator =(A ThatConst() &a) ThisConst() \
278
typename boost::proto::base_expr< \
280
, boost::proto::tag::assign \
281
, boost::proto::list2< \
282
proto_derived_expr ThisConst() & \
283
, typename boost::proto::result_of::as_child<A ThatConst(), proto_domain>::type \
287
that_type const that = { \
288
*static_cast<proto_derived_expr ThisConst() *>(this) \
289
, boost::proto::as_child<proto_domain>(a) \
291
return proto_generator()(that); \
295
#define BOOST_PROTO_EXTENDS_ASSIGN_CONST_() \
296
BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PROTO_CONST, BOOST_PP_EMPTY) \
297
BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PROTO_CONST, BOOST_PROTO_CONST) \
300
#define BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST_() \
301
BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PP_EMPTY, BOOST_PP_EMPTY) \
302
BOOST_PROTO_EXTENDS_ASSIGN_IMPL_(BOOST_PP_EMPTY, BOOST_PROTO_CONST) \
305
#define BOOST_PROTO_EXTENDS_ASSIGN_() \
306
BOOST_PROTO_EXTENDS_ASSIGN_CONST_() \
307
BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST_() \
310
#define BOOST_PROTO_EXTENDS_ASSIGN_CONST() \
311
BOOST_PROTO_EXTENDS_COPY_ASSIGN_(proto_derived_expr, BOOST_PROTO_TYPENAME) \
312
BOOST_PROTO_EXTENDS_ASSIGN_CONST_() \
315
#define BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST() \
316
BOOST_PROTO_EXTENDS_COPY_ASSIGN_(proto_derived_expr, BOOST_PROTO_TYPENAME) \
317
BOOST_PROTO_EXTENDS_ASSIGN_NON_CONST_() \
320
#define BOOST_PROTO_EXTENDS_ASSIGN() \
321
BOOST_PROTO_EXTENDS_COPY_ASSIGN_(proto_derived_expr, BOOST_PROTO_TYPENAME) \
322
BOOST_PROTO_EXTENDS_ASSIGN_() \
327
#define BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(ThisConst, ThatConst) \
328
template<typename A> \
330
typename BOOST_PROTO_RESULT_OF< \
332
typename boost::proto::base_expr< \
334
, boost::proto::tag::subscript \
335
, boost::proto::list2< \
336
proto_derived_expr ThisConst() & \
337
, typename boost::proto::result_of::as_child<A ThatConst(), proto_domain>::type \
342
operator [](A ThatConst() &a) ThisConst() \
345
typename boost::proto::base_expr< \
347
, boost::proto::tag::subscript \
348
, boost::proto::list2< \
349
proto_derived_expr ThisConst() & \
350
, typename boost::proto::result_of::as_child<A ThatConst(), proto_domain>::type \
354
that_type const that = { \
355
*static_cast<proto_derived_expr ThisConst() *>(this) \
356
, boost::proto::as_child<proto_domain>(a) \
358
return proto_generator()(that); \
362
#define BOOST_PROTO_EXTENDS_SUBSCRIPT_CONST() \
363
BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PROTO_CONST, BOOST_PP_EMPTY) \
364
BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PROTO_CONST, BOOST_PROTO_CONST) \
367
#define BOOST_PROTO_EXTENDS_SUBSCRIPT_NON_CONST() \
368
BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PP_EMPTY, BOOST_PP_EMPTY) \
369
BOOST_PROTO_EXTENDS_SUBSCRIPT_IMPL_(BOOST_PP_EMPTY, BOOST_PROTO_CONST) \
372
#define BOOST_PROTO_EXTENDS_SUBSCRIPT() \
373
BOOST_PROTO_EXTENDS_SUBSCRIPT_CONST() \
374
BOOST_PROTO_EXTENDS_SUBSCRIPT_NON_CONST() \
379
#define BOOST_PROTO_EXTENDS_FUNCTION_() \
380
template<typename Sig> \
384
typename BOOST_PROTO_RESULT_OF< \
386
typename boost::proto::result_of::funop< \
388
, proto_derived_expr \
397
#ifndef BOOST_NO_VARIADIC_TEMPLATES
398
#define BOOST_PROTO_EXTENDS_FUNCTION_CONST() \
399
BOOST_PROTO_EXTENDS_FUNCTION_() \
400
BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PROTO_CONST) \
403
#define BOOST_PROTO_EXTENDS_FUNCTION_NON_CONST() \
404
BOOST_PROTO_EXTENDS_FUNCTION_() \
405
BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PP_EMPTY) \
408
#define BOOST_PROTO_EXTENDS_FUNCTION() \
409
BOOST_PROTO_EXTENDS_FUNCTION_() \
410
BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PP_EMPTY) \
411
BOOST_PROTO_DEFINE_FUN_OP_VARIADIC_IMPL_(BOOST_PROTO_CONST) \
414
#define BOOST_PROTO_EXTENDS_FUNCTION_CONST() \
415
BOOST_PROTO_EXTENDS_FUNCTION_() \
416
BOOST_PP_REPEAT_FROM_TO( \
418
, BOOST_PROTO_MAX_FUNCTION_CALL_ARITY \
419
, BOOST_PROTO_DEFINE_FUN_OP_CONST \
424
#define BOOST_PROTO_EXTENDS_FUNCTION_NON_CONST() \
425
BOOST_PROTO_EXTENDS_FUNCTION_() \
426
BOOST_PP_REPEAT_FROM_TO( \
428
, BOOST_PROTO_MAX_FUNCTION_CALL_ARITY \
429
, BOOST_PROTO_DEFINE_FUN_OP_NON_CONST \
434
#define BOOST_PROTO_EXTENDS_FUNCTION() \
435
BOOST_PROTO_EXTENDS_FUNCTION_() \
436
BOOST_PP_REPEAT_FROM_TO( \
438
, BOOST_PROTO_MAX_FUNCTION_CALL_ARITY \
439
, BOOST_PROTO_DEFINE_FUN_OP \
445
#define BOOST_PROTO_EXTENDS(Expr, Derived, Domain) \
446
BOOST_PROTO_BASIC_EXTENDS(Expr, Derived, Domain) \
447
BOOST_PROTO_EXTENDS_ASSIGN() \
448
BOOST_PROTO_EXTENDS_SUBSCRIPT() \
449
BOOST_PROTO_EXTENDS_FUNCTION() \
452
#define BOOST_PROTO_EXTENDS_USING_ASSIGN(Derived) \
453
typedef typename Derived::proto_extends proto_extends; \
454
using proto_extends::operator =; \
455
BOOST_PROTO_EXTENDS_COPY_ASSIGN_(Derived, BOOST_PROTO_TYPENAME) \
458
#define BOOST_PROTO_EXTENDS_USING_ASSIGN_NON_DEPENDENT(Derived) \
459
typedef Derived::proto_extends proto_extends; \
460
using proto_extends::operator =; \
461
BOOST_PROTO_EXTENDS_COPY_ASSIGN_(Derived, BOOST_PP_EMPTY) \
466
/// \brief Empty type to be used as a dummy template parameter of
467
/// POD expression wrappers. It allows argument-dependent lookup
468
/// to find Proto's operator overloads.
470
/// \c proto::is_proto_expr allows argument-dependent lookup
471
/// to find Proto's operator overloads. For example:
474
/// template<typename T, typename Dummy = proto::is_proto_expr>
475
/// struct my_terminal
477
/// BOOST_PROTO_BASIC_EXTENDS(
478
/// typename proto::terminal<T>::type
485
/// my_terminal<int> _1, _2;
486
/// _1 + _2; // OK, uses proto::operator+
489
/// Without the second \c Dummy template parameter, Proto's operator
490
/// overloads would not be considered by name lookup.
494
/// \brief extends\<\> class template for adding behaviors to a Proto expression template
499
, typename Domain // = proto::default_domain
500
, long Arity // = Expr::proto_arity_c
510
extends(extends const &that)
511
: proto_expr_(that.proto_expr_)
515
extends(Expr const &expr_)
519
typedef extends proto_extends;
520
BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, typename Domain)
521
BOOST_PROTO_EXTENDS_ASSIGN_CONST_()
522
BOOST_PROTO_EXTENDS_SUBSCRIPT_CONST()
524
// Instead of using BOOST_PROTO_EXTENDS_FUNCTION, which uses
525
// nested preprocessor loops, use file iteration here to generate
526
// the operator() overloads, which is more efficient.
527
#include <boost/proto/detail/extends_funop_const.hpp>
530
/// \brief extends\<\> class template for adding behaviors to a Proto expression template
532
template<typename Expr, typename Derived, typename Domain>
533
struct extends<Expr, Derived, Domain, 0>
541
extends(extends const &that)
542
: proto_expr_(that.proto_expr_)
546
extends(Expr const &expr_)
550
typedef extends proto_extends;
551
BOOST_PROTO_BASIC_EXTENDS_(Expr, Derived, typename Domain)
552
BOOST_PROTO_EXTENDS_ASSIGN_()
553
BOOST_PROTO_EXTENDS_SUBSCRIPT()
555
// Instead of using BOOST_PROTO_EXTENDS_FUNCTION, which uses
556
// nested preprocessor loops, use file iteration here to generate
557
// the operator() overloads, which is more efficient.
558
#include <boost/proto/detail/extends_funop.hpp>
563
template<typename This, typename Fun, typename Domain>
564
struct virtual_member
566
typedef Domain proto_domain;
567
typedef typename Domain::proto_generator proto_generator;
568
typedef virtual_member<This, Fun, Domain> proto_derived_expr;
569
typedef tag::member proto_tag;
570
typedef list2<This &, expr<tag::terminal, term<Fun> > const &> proto_args;
571
typedef mpl::long_<2> proto_arity;
572
typedef detail::not_a_valid_type proto_address_of_hack_type_;
573
typedef void proto_is_expr_; /**< INTERNAL ONLY */
574
static const long proto_arity_c = 2;
575
typedef boost::proto::tag::proto_expr fusion_tag;
576
typedef This &proto_child0;
577
typedef expr<tag::terminal, term<Fun> > const &proto_child1;
578
typedef expr<proto_tag, proto_args, proto_arity_c> proto_base_expr;
579
typedef basic_expr<proto_tag, proto_args, proto_arity_c> proto_grammar;
580
typedef void proto_is_aggregate_; /**< INTERNAL ONLY */
582
BOOST_PROTO_EXTENDS_ASSIGN_()
583
BOOST_PROTO_EXTENDS_SUBSCRIPT()
585
// Instead of using BOOST_PROTO_EXTENDS_FUNCTION, which uses
586
// nested preprocessor loops, use file iteration here to generate
587
// the operator() overloads, which is more efficient.
588
#define BOOST_PROTO_NO_WAVE_OUTPUT
589
#include <boost/proto/detail/extends_funop.hpp>
590
#undef BOOST_PROTO_NO_WAVE_OUTPUT
593
proto_base_expr const proto_base() const
595
proto_base_expr that = {this->child0(), this->child1()};
600
proto_child0 child0() const
603
return *(This *)((char *)this - BOOST_PROTO_OFFSETOF(This, proto_member_union_start_));
607
proto_child1 child1() const
609
static expr<tag::terminal, term<Fun>, 0> const that = {Fun()};
616
#define BOOST_PROTO_EXTENDS_MEMBER_(R, DOMAIN, ELEM) \
617
boost::proto::exprns_::virtual_member< \
619
, BOOST_PP_TUPLE_ELEM(2, 0, ELEM) \
621
> BOOST_PP_TUPLE_ELEM(2, 1, ELEM); \
624
/// \brief For declaring virtual data members in an extension class.
626
#define BOOST_PROTO_EXTENDS_MEMBERS_WITH_DOMAIN(SEQ, DOMAIN) \
629
char proto_member_union_start_; \
630
BOOST_PP_SEQ_FOR_EACH(BOOST_PROTO_EXTENDS_MEMBER_, DOMAIN, SEQ) \
634
/// \brief For declaring virtual data members in an extension class.
636
#define BOOST_PROTO_EXTENDS_MEMBERS(SEQ) \
637
BOOST_PROTO_EXTENDS_MEMBERS_WITH_DOMAIN(SEQ, proto_domain) \