]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright (c) 2001-2011 Hartmut Kaiser |
2 | // | |
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) | |
5 | ||
6 | #if !defined(BOOST_SPIRIT_SUPPORT_META_CREATE_NOV_21_2009_0327PM) | |
7 | #define BOOST_SPIRIT_SUPPORT_META_CREATE_NOV_21_2009_0327PM | |
8 | ||
9 | #if defined(_MSC_VER) | |
10 | #pragma once | |
11 | #endif | |
12 | ||
13 | #include <boost/spirit/home/support/unused.hpp> | |
14 | ||
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> | |
26 | ||
27 | // needed for workaround below | |
28 | #if defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ < 3)) | |
29 | #include <boost/type_traits/is_same.hpp> | |
30 | #endif | |
31 | ||
32 | namespace boost { namespace spirit { namespace traits | |
33 | { | |
34 | /////////////////////////////////////////////////////////////////////////// | |
35 | // This is the main dispatch point for meta_create to the correct domain | |
36 | template <typename Domain, typename T, typename Enable = void> | |
37 | struct meta_create; | |
38 | ||
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_ {}; | |
44 | }}} | |
45 | ||
46 | namespace boost { namespace spirit | |
47 | { | |
48 | /////////////////////////////////////////////////////////////////////////// | |
49 | namespace detail | |
50 | { | |
51 | template <typename T> | |
52 | struct add_const_ref | |
53 | : add_reference<typename add_const<T>::type> {}; | |
54 | ||
55 | template <typename T> | |
56 | struct remove_const_ref | |
57 | : remove_const<typename remove_reference<T>::type> {}; | |
58 | ||
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 | |
66 | { | |
67 | template <typename T> | |
68 | struct result; | |
69 | ||
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)> | |
75 | { | |
76 | BOOST_STATIC_ASSERT((is_same<F, nary_proto_expr_function>::value)); | |
77 | #else | |
78 | template <typename T1, typename T2> | |
79 | struct result<nary_proto_expr_function(T1, T2)> | |
80 | { | |
81 | #endif | |
82 | typedef typename remove_const_ref<T2>::type left_type; | |
83 | typedef typename | |
84 | spirit::traits::meta_create<Domain, T1>::type | |
85 | right_type; | |
86 | ||
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> | |
91 | >::type type; | |
92 | }; | |
93 | ||
94 | template <typename T> | |
95 | typename result<nary_proto_expr_function(T, unused_type const&)>::type | |
96 | operator()(T, unused_type const&) const | |
97 | { | |
98 | typedef spirit::traits::meta_create<Domain, T> right_type; | |
99 | return right_type::call(); | |
100 | } | |
101 | ||
102 | template <typename T1, typename T2> | |
103 | typename result<nary_proto_expr_function(T1, T2)>::type | |
104 | operator()(T1, T2 const& t2) const | |
105 | { | |
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()); | |
109 | } | |
110 | }; | |
111 | #else | |
112 | /////////////////////////////////////////////////////////////////////// | |
113 | template <typename OpTag, typename Domain> | |
114 | struct nary_proto_expr_function | |
115 | { | |
116 | template <typename T> | |
117 | struct result; | |
118 | ||
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)> | |
124 | { | |
125 | BOOST_STATIC_ASSERT((is_same<F, nary_proto_expr_function>::value)); | |
126 | #else | |
127 | template <typename T1, typename T2> | |
128 | struct result<nary_proto_expr_function(T1, T2)> | |
129 | { | |
130 | #endif | |
131 | typedef typename remove_const_ref<T1>::type left_type; | |
132 | typedef typename | |
133 | spirit::traits::meta_create<Domain, T2>::type | |
134 | right_type; | |
135 | ||
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> | |
140 | >::type type; | |
141 | }; | |
142 | ||
143 | template <typename T> | |
144 | typename result<nary_proto_expr_function(unused_type const&, T)>::type | |
145 | operator()(unused_type const&, T) const | |
146 | { | |
147 | typedef spirit::traits::meta_create<Domain, T> right_type; | |
148 | return right_type::call(); | |
149 | } | |
150 | ||
151 | template <typename T1, typename T2> | |
152 | typename result<nary_proto_expr_function(T1, T2)>::type | |
153 | operator()(T1 const& t1, T2) const | |
154 | { | |
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()); | |
158 | } | |
159 | }; | |
160 | #endif | |
161 | } | |
162 | ||
163 | /////////////////////////////////////////////////////////////////////// | |
164 | template <typename T, typename OpTag, typename Domain> | |
165 | struct make_unary_proto_expr | |
166 | { | |
167 | typedef spirit::traits::meta_create<Domain, T> subject_type; | |
168 | ||
169 | typedef typename proto::result_of::make_expr< | |
170 | OpTag, typename subject_type::type | |
171 | >::type type; | |
172 | ||
173 | static type call() | |
174 | { | |
175 | return proto::make_expr<OpTag>(subject_type::call()); | |
176 | } | |
177 | }; | |
178 | ||
179 | /////////////////////////////////////////////////////////////////////////// | |
180 | template <typename Sequence, typename OpTag, typename Domain> | |
181 | struct make_nary_proto_expr | |
182 | { | |
183 | typedef detail::nary_proto_expr_function<OpTag, Domain> | |
184 | make_proto_expr; | |
185 | ||
186 | typedef typename fusion::result_of::fold< | |
187 | Sequence, unused_type, make_proto_expr | |
188 | >::type type; | |
189 | ||
190 | static type call() | |
191 | { | |
192 | return fusion::fold(Sequence(), unused, make_proto_expr()); | |
193 | } | |
194 | }; | |
195 | ||
196 | /////////////////////////////////////////////////////////////////////////// | |
197 | namespace detail | |
198 | { | |
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 | |
205 | : mpl::and_< | |
206 | fusion::traits::is_sequence<T> | |
207 | , mpl::not_<proto::is_expr<T> > > | |
208 | {}; | |
209 | } | |
210 | }} | |
211 | ||
212 | #endif |