1 // Copyright (c) 2001-2011 Hartmut Kaiser
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 #if !defined(BOOST_SPIRIT_SUPPORT_META_CREATE_NOV_21_2009_0327PM)
7 #define BOOST_SPIRIT_SUPPORT_META_CREATE_NOV_21_2009_0327PM
13 #include <boost/spirit/home/support/unused.hpp>
15 #include <boost/version.hpp>
16 #include <boost/spirit/include/phoenix_limits.hpp> // needs to be included before proto
17 #include <boost/proto/proto.hpp>
18 #include <boost/utility/result_of.hpp>
19 #include <boost/type_traits/add_const.hpp>
20 #include <boost/type_traits/add_reference.hpp>
21 #include <boost/type_traits/remove_const.hpp>
22 #include <boost/type_traits/remove_reference.hpp>
23 #include <boost/fusion/include/fold.hpp>
24 #include <boost/mpl/and.hpp>
25 #include <boost/mpl/not.hpp>
27 // needed for workaround below
28 #if defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ < 3))
29 #include <boost/type_traits/is_same.hpp>
32 namespace boost { namespace spirit { namespace traits
34 ///////////////////////////////////////////////////////////////////////////
35 // This is the main dispatch point for meta_create to the correct domain
36 template <typename Domain, typename T, typename Enable = void>
39 ///////////////////////////////////////////////////////////////////////////
40 // This allows to query whether a valid mapping exists for the given data
41 // type to a component in the given domain
42 template <typename Domain, typename T, typename Enable = void>
43 struct meta_create_exists : mpl::false_ {};
46 namespace boost { namespace spirit
48 ///////////////////////////////////////////////////////////////////////////
53 : add_reference<typename add_const<T>::type> {};
56 struct remove_const_ref
57 : remove_const<typename remove_reference<T>::type> {};
59 // starting with Boost V1.42 fusion::fold has been changed to be compatible
60 // with mpl::fold (the sequence of template parameters for the meta-function
61 // object has been changed)
62 #if BOOST_VERSION < 104200
63 ///////////////////////////////////////////////////////////////////////
64 template <typename OpTag, typename Domain>
65 struct nary_proto_expr_function
70 // this is a workaround for older versions of g++ (< V4.3) which apparently have
71 // problems with the following template specialization
72 #if defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ < 3))
73 template <typename F, typename T1, typename T2>
74 struct result<F(T1, T2)>
76 BOOST_STATIC_ASSERT((is_same<F, nary_proto_expr_function>::value));
78 template <typename T1, typename T2>
79 struct result<nary_proto_expr_function(T1, T2)>
82 typedef typename remove_const_ref<T2>::type left_type;
84 spirit::traits::meta_create<Domain, T1>::type
87 typedef typename mpl::eval_if<
88 traits::not_is_unused<left_type>
89 , proto::result_of::make_expr<OpTag, left_type, right_type>
90 , mpl::identity<right_type>
95 typename result<nary_proto_expr_function(T, unused_type const&)>::type
96 operator()(T, unused_type const&) const
98 typedef spirit::traits::meta_create<Domain, T> right_type;
99 return right_type::call();
102 template <typename T1, typename T2>
103 typename result<nary_proto_expr_function(T1, T2)>::type
104 operator()(T1, T2 const& t2) const
106 // we variants to the alternative operator
107 typedef spirit::traits::meta_create<Domain, T1> right_type;
108 return proto::make_expr<OpTag>(t2, right_type::call());
112 ///////////////////////////////////////////////////////////////////////
113 template <typename OpTag, typename Domain>
114 struct nary_proto_expr_function
116 template <typename T>
119 // this is a workaround for older versions of g++ (< V4.3) which apparently have
120 // problems with the following template specialization
121 #if defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ < 3))
122 template <typename F, typename T1, typename T2>
123 struct result<F(T1, T2)>
125 BOOST_STATIC_ASSERT((is_same<F, nary_proto_expr_function>::value));
127 template <typename T1, typename T2>
128 struct result<nary_proto_expr_function(T1, T2)>
131 typedef typename remove_const_ref<T1>::type left_type;
133 spirit::traits::meta_create<Domain, T2>::type
136 typedef typename mpl::eval_if<
137 traits::not_is_unused<left_type>
138 , proto::result_of::make_expr<OpTag, left_type, right_type>
139 , mpl::identity<right_type>
143 template <typename T>
144 typename result<nary_proto_expr_function(unused_type const&, T)>::type
145 operator()(unused_type const&, T) const
147 typedef spirit::traits::meta_create<Domain, T> right_type;
148 return right_type::call();
151 template <typename T1, typename T2>
152 typename result<nary_proto_expr_function(T1, T2)>::type
153 operator()(T1 const& t1, T2) const
155 // we variants to the alternative operator
156 typedef spirit::traits::meta_create<Domain, T2> right_type;
157 return proto::make_expr<OpTag>(t1, right_type::call());
163 ///////////////////////////////////////////////////////////////////////
164 template <typename T, typename OpTag, typename Domain>
165 struct make_unary_proto_expr
167 typedef spirit::traits::meta_create<Domain, T> subject_type;
169 typedef typename proto::result_of::make_expr<
170 OpTag, typename subject_type::type
175 return proto::make_expr<OpTag>(subject_type::call());
179 ///////////////////////////////////////////////////////////////////////////
180 template <typename Sequence, typename OpTag, typename Domain>
181 struct make_nary_proto_expr
183 typedef detail::nary_proto_expr_function<OpTag, Domain>
186 typedef typename fusion::result_of::fold<
187 Sequence, unused_type, make_proto_expr
192 return fusion::fold(Sequence(), unused, make_proto_expr());
196 ///////////////////////////////////////////////////////////////////////////
199 // Starting with newer versions of Proto, all Proto expressions are at
200 // the same time Fusion sequences. This is the correct behavior, but
201 // we need to distinguish between Fusion sequences and Proto
202 // expressions. This meta-function does exactly that.
203 template <typename T>
204 struct is_fusion_sequence_but_not_proto_expr
206 fusion::traits::is_sequence<T>
207 , mpl::not_<proto::is_expr<T> > >