1 /*=============================================================================
2 Copyright (c) 2012 Nathan Ridge
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 ==============================================================================*/
8 #ifndef BOOST_FUSION_ADAPTED_STRUCT_DETAIL_DEFINE_STRUCT_INLINE_HPP
9 #define BOOST_FUSION_ADAPTED_STRUCT_DETAIL_DEFINE_STRUCT_INLINE_HPP
11 #include <boost/fusion/support/config.hpp>
12 #include <boost/config.hpp>
13 #include <boost/fusion/support/category_of.hpp>
14 #include <boost/fusion/sequence/sequence_facade.hpp>
15 #include <boost/fusion/iterator/iterator_facade.hpp>
16 #include <boost/fusion/algorithm/auxiliary/copy.hpp>
17 #include <boost/fusion/adapted/struct/detail/define_struct.hpp>
18 #include <boost/mpl/int.hpp>
19 #include <boost/mpl/bool.hpp>
20 #include <boost/mpl/identity.hpp>
21 #include <boost/mpl/minus.hpp>
22 #include <boost/mpl/if.hpp>
23 #include <boost/type_traits/is_const.hpp>
24 #include <boost/preprocessor/comma_if.hpp>
25 #include <boost/preprocessor/facilities/is_empty.hpp>
26 #include <boost/preprocessor/repeat.hpp>
27 #include <boost/preprocessor/seq/for_each_i.hpp>
28 #include <boost/preprocessor/seq/size.hpp>
29 #include <boost/preprocessor/seq/enum.hpp>
30 #include <boost/preprocessor/seq/seq.hpp>
31 #include <boost/preprocessor/tuple/elem.hpp>
33 // MSVC and GCC <= 4.4 have a bug that affects partial specializations of
34 // nested templates under some circumstances. This affects the implementation
35 // of BOOST_FUSION_DEFINE_STRUCT_INLINE, which uses such specializations for
36 // the iterator class's 'deref' and 'value_of' metafunctions. On these compilers
37 // an alternate implementation for these metafunctions is used that does not
38 // require such specializations. The alternate implementation takes longer
39 // to compile so its use is restricted to the offending compilers.
40 // For MSVC, the bug was reported at https://connect.microsoft.com/VisualStudio/feedback/details/757891/c-compiler-error-involving-partial-specializations-of-nested-templates
41 // For GCC, 4.4 and earlier are no longer maintained so there is no need
43 #if defined(BOOST_MSVC) || (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ <= 4)))
44 #define BOOST_FUSION_NEED_NESTED_TEMPLATE_PARTIAL_SPEC_WKND
47 #ifdef BOOST_FUSION_NEED_NESTED_TEMPLATE_PARTIAL_SPEC_WKND
48 #include <boost/type_traits/add_const.hpp>
49 #include <boost/type_traits/remove_const.hpp>
50 #include <boost/mpl/if.hpp>
51 #include <boost/fusion/sequence/intrinsic/at_c.hpp>
52 #include <boost/fusion/container/vector.hpp>
56 #define BOOST_FUSION_MAKE_DEFAULT_INIT_LIST_ENTRY(R, DATA, N, ATTRIBUTE) \
57 BOOST_PP_COMMA_IF(N) BOOST_PP_TUPLE_ELEM(2, 1, ATTRIBUTE)()
59 #define BOOST_FUSION_MAKE_DEFAULT_INIT_LIST(ATTRIBUTES_SEQ) \
60 : BOOST_PP_SEQ_FOR_EACH_I( \
61 BOOST_FUSION_MAKE_DEFAULT_INIT_LIST_ENTRY, \
65 #define BOOST_FUSION_IGNORE_1(ARG1)
66 #define BOOST_FUSION_IGNORE_2(ARG1, ARG2)
68 #define BOOST_FUSION_MAKE_COPY_CONSTRUCTOR(NAME, ATTRIBUTES_SEQ) \
69 NAME(BOOST_PP_SEQ_FOR_EACH_I( \
70 BOOST_FUSION_MAKE_CONST_REF_PARAM, \
73 : BOOST_PP_SEQ_FOR_EACH_I( \
74 BOOST_FUSION_MAKE_INIT_LIST_ENTRY, \
80 #define BOOST_FUSION_MAKE_CONST_REF_PARAM(R, DATA, N, ATTRIBUTE) \
81 BOOST_PP_COMMA_IF(N) \
82 BOOST_PP_TUPLE_ELEM(2, 0, ATTRIBUTE) const& \
83 BOOST_PP_TUPLE_ELEM(2, 1, ATTRIBUTE)
85 #define BOOST_FUSION_MAKE_INIT_LIST_ENTRY_I(NAME) NAME(NAME)
87 #define BOOST_FUSION_MAKE_INIT_LIST_ENTRY(R, DATA, N, ATTRIBUTE) \
88 BOOST_PP_COMMA_IF(N) \
89 BOOST_FUSION_MAKE_INIT_LIST_ENTRY_I(BOOST_PP_TUPLE_ELEM(2, 1, ATTRIBUTE))
91 #define BOOST_FUSION_ITERATOR_NAME(NAME) \
92 BOOST_PP_CAT(boost_fusion_detail_, BOOST_PP_CAT(NAME, _iterator))
94 // Note: all template parameter names need to be uglified, otherwise they might
95 // shadow a template parameter of the struct when used with
96 // BOOST_FUSION_DEFINE_TPL_STRUCT_INLINE
98 #define BOOST_FUSION_MAKE_ITERATOR_VALUE_OF_SPECS(Z, N, NAME) \
99 template <typename boost_fusion_detail_Sq> \
101 BOOST_FUSION_ITERATOR_NAME(NAME)<boost_fusion_detail_Sq, N> \
103 : boost::mpl::identity< \
104 typename boost_fusion_detail_Sq::t##N##_type \
109 #define BOOST_FUSION_MAKE_ITERATOR_DEREF_SPEC( \
110 SPEC_TYPE, CALL_ARG_TYPE, TYPE_QUAL, ATTRIBUTE, N) \
112 template <typename boost_fusion_detail_Sq> \
113 struct deref<SPEC_TYPE, N> > \
115 typedef typename boost_fusion_detail_Sq::t##N##_type TYPE_QUAL& type; \
116 BOOST_FUSION_GPU_ENABLED \
117 static type call(CALL_ARG_TYPE, N> const& iter) \
119 return iter.seq_.BOOST_PP_TUPLE_ELEM(2, 1, ATTRIBUTE); \
123 #define BOOST_FUSION_MAKE_ITERATOR_DEREF_SPECS(R, NAME, N, ATTRIBUTE) \
124 BOOST_FUSION_MAKE_ITERATOR_DEREF_SPEC( \
125 BOOST_FUSION_ITERATOR_NAME(NAME)<boost_fusion_detail_Sq, \
126 BOOST_FUSION_ITERATOR_NAME(NAME)<boost_fusion_detail_Sq, \
130 BOOST_FUSION_MAKE_ITERATOR_DEREF_SPEC( \
131 BOOST_FUSION_ITERATOR_NAME(NAME)<const boost_fusion_detail_Sq, \
132 BOOST_FUSION_ITERATOR_NAME(NAME)<const boost_fusion_detail_Sq, \
136 BOOST_FUSION_MAKE_ITERATOR_DEREF_SPEC( \
137 const BOOST_FUSION_ITERATOR_NAME(NAME)<boost_fusion_detail_Sq, \
138 BOOST_FUSION_ITERATOR_NAME(NAME)<boost_fusion_detail_Sq, \
142 BOOST_FUSION_MAKE_ITERATOR_DEREF_SPEC( \
143 const BOOST_FUSION_ITERATOR_NAME(NAME)<const boost_fusion_detail_Sq, \
144 BOOST_FUSION_ITERATOR_NAME(NAME)<const boost_fusion_detail_Sq, \
149 #define BOOST_FUSION_MAKE_VALUE_AT_SPECS(Z, N, DATA) \
150 template <typename boost_fusion_detail_Sq> \
151 struct value_at<boost_fusion_detail_Sq, boost::mpl::int_<N> > \
153 typedef typename boost_fusion_detail_Sq::t##N##_type type; \
156 #define BOOST_FUSION_MAKE_AT_SPECS(R, DATA, N, ATTRIBUTE) \
157 template <typename boost_fusion_detail_Sq> \
158 struct at<boost_fusion_detail_Sq, boost::mpl::int_<N> > \
160 typedef typename boost::mpl::if_< \
161 boost::is_const<boost_fusion_detail_Sq>, \
162 typename boost_fusion_detail_Sq::t##N##_type const&, \
163 typename boost_fusion_detail_Sq::t##N##_type& \
166 BOOST_FUSION_GPU_ENABLED \
167 static type call(boost_fusion_detail_Sq& sq) \
169 return sq. BOOST_PP_TUPLE_ELEM(2, 1, ATTRIBUTE); \
173 #define BOOST_FUSION_MAKE_TYPEDEF(R, DATA, N, ATTRIBUTE) \
174 typedef BOOST_PP_TUPLE_ELEM(2, 0, ATTRIBUTE) t##N##_type;
176 #define BOOST_FUSION_MAKE_DATA_MEMBER(R, DATA, N, ATTRIBUTE) \
177 BOOST_PP_TUPLE_ELEM(2, 0, ATTRIBUTE) BOOST_PP_TUPLE_ELEM(2, 1, ATTRIBUTE);
179 #ifdef BOOST_FUSION_NEED_NESTED_TEMPLATE_PARTIAL_SPEC_WKND
181 #define BOOST_FUSION_DEFINE_ITERATOR_VALUE_OF(NAME, ATTRIBUTE_SEQ_SIZE) \
182 template <typename boost_fusion_detail_Iterator> \
183 struct value_of : boost::fusion::result_of::at_c< \
185 boost_fusion_detail_Iterator::index::value \
190 #define BOOST_FUSION_DEFINE_ITERATOR_DEREF(NAME, ATTRIBUTES_SEQ) \
191 template <typename boost_fusion_detail_Iterator> \
194 typedef typename boost::remove_const< \
195 boost_fusion_detail_Iterator \
196 >::type iterator_raw_type; \
198 static const int index = iterator_raw_type::index::value; \
200 typedef typename boost::fusion::result_of::at_c< \
203 >::type result_raw_type; \
205 typedef typename boost::mpl::if_< \
206 boost::is_const<typename iterator_raw_type::sequence_type>, \
207 typename boost::add_const<result_raw_type>::type, \
211 BOOST_FUSION_GPU_ENABLED \
212 static type call(iterator_raw_type const& iter) \
214 return boost::fusion::at_c<index>(iter.ref_vec); \
218 #define BOOST_FUSION_MAKE_ITERATOR_WKND_FIELD_NAME(R, DATA, N, ATTRIBUTE) \
219 BOOST_PP_COMMA_IF(N) seq.BOOST_PP_TUPLE_ELEM(2, 1, ATTRIBUTE)
221 #define BOOST_FUSION_DEFINE_ITERATOR_WKND_INIT_LIST_ENTRIES(ATTRIBUTES_SEQ) \
222 , ref_vec(BOOST_PP_SEQ_FOR_EACH_I( \
223 BOOST_FUSION_MAKE_ITERATOR_WKND_FIELD_NAME, \
225 BOOST_PP_SEQ_TAIL(ATTRIBUTES_SEQ)))
227 #define BOOST_FUSION_MAKE_ITERATOR_WKND_REF(Z, N, DATA) \
228 BOOST_PP_COMMA_IF(N) \
229 typename boost::mpl::if_< \
230 boost::is_const<boost_fusion_detail_Seq>, \
231 typename boost::add_const< \
232 typename boost_fusion_detail_Seq::t##N##_type \
234 typename boost_fusion_detail_Seq::t##N##_type \
237 #define BOOST_FUSION_DEFINE_ITERATOR_WKND_MEMBERS(ATTRIBUTES_SEQ_SIZE) \
238 typedef boost::fusion::vector< \
240 ATTRIBUTES_SEQ_SIZE, \
241 BOOST_FUSION_MAKE_ITERATOR_WKND_REF, \
249 #define BOOST_FUSION_DEFINE_ITERATOR_VALUE_OF(NAME, ATTRIBUTES_SEQ_SIZE) \
250 template <typename boost_fusion_detail_T> struct value_of; \
252 ATTRIBUTES_SEQ_SIZE, \
253 BOOST_FUSION_MAKE_ITERATOR_VALUE_OF_SPECS, \
256 #define BOOST_FUSION_DEFINE_ITERATOR_DEREF(NAME, ATTRIBUTES_SEQ) \
257 template <typename boost_fusion_detail_T> struct deref; \
258 BOOST_PP_SEQ_FOR_EACH_I( \
259 BOOST_FUSION_MAKE_ITERATOR_DEREF_SPECS, \
263 #define BOOST_FUSION_DEFINE_ITERATOR_WKND_INIT_LIST_ENTRIES(ATTRIBUTES_SEQ)
265 #define BOOST_FUSION_DEFINE_ITERATOR_WKND_MEMBERS(ATTRIBUTES_SEQ_SIZE)
267 #endif // BOOST_FUSION_NEED_NESTED_TEMPLATE_PARTIAL_SPEC_WKND
269 // Note: We can't nest the iterator inside the struct because we run into
270 // a MSVC10 bug involving partial specializations of nested templates.
272 #define BOOST_FUSION_DEFINE_STRUCT_INLINE_IMPL(NAME, ATTRIBUTES) \
273 BOOST_FUSION_DEFINE_STRUCT_INLINE_ITERATOR(NAME, ATTRIBUTES) \
274 struct NAME : boost::fusion::sequence_facade< \
276 boost::fusion::random_access_traversal_tag \
279 BOOST_FUSION_DEFINE_STRUCT_INLINE_MEMBERS(NAME, ATTRIBUTES) \
282 #define BOOST_FUSION_DEFINE_TPL_STRUCT_INLINE_IMPL( \
283 TEMPLATE_PARAMS_SEQ, NAME, ATTRIBUTES) \
285 BOOST_FUSION_DEFINE_STRUCT_INLINE_ITERATOR(NAME, ATTRIBUTES) \
288 BOOST_FUSION_ADAPT_STRUCT_UNPACK_TEMPLATE_PARAMS_IMPL( \
289 (0)TEMPLATE_PARAMS_SEQ) \
291 struct NAME : boost::fusion::sequence_facade< \
293 BOOST_PP_SEQ_ENUM(TEMPLATE_PARAMS_SEQ) \
295 boost::fusion::random_access_traversal_tag \
298 BOOST_FUSION_DEFINE_STRUCT_INLINE_MEMBERS(NAME, ATTRIBUTES) \
301 #define BOOST_FUSION_DEFINE_STRUCT_INLINE_MEMBERS(NAME, ATTRIBUTES) \
302 BOOST_FUSION_DEFINE_STRUCT_MEMBERS_IMPL( \
304 BOOST_PP_CAT(BOOST_FUSION_ADAPT_STRUCT_FILLER_0 ATTRIBUTES,_END))
306 // Note: can't compute BOOST_PP_SEQ_SIZE(ATTRIBUTES_SEQ) directly because
307 // ATTRIBUTES_SEQ may be empty and calling BOOST_PP_SEQ_SIZE on an empty
308 // sequence produces warnings on MSVC.
309 #define BOOST_FUSION_DEFINE_STRUCT_MEMBERS_IMPL(NAME, ATTRIBUTES_SEQ) \
310 BOOST_FUSION_DEFINE_STRUCT_INLINE_MEMBERS_IMPL_IMPL( \
313 BOOST_PP_DEC(BOOST_PP_SEQ_SIZE((0)ATTRIBUTES_SEQ)))
315 #define BOOST_FUSION_DEFINE_STRUCT_INLINE_ITERATOR(NAME, ATTRIBUTES) \
316 BOOST_FUSION_DEFINE_STRUCT_ITERATOR_IMPL( \
318 BOOST_PP_CAT(BOOST_FUSION_ADAPT_STRUCT_FILLER_0 ATTRIBUTES,_END))
320 #define BOOST_FUSION_DEFINE_STRUCT_ITERATOR_IMPL(NAME, ATTRIBUTES_SEQ) \
321 BOOST_FUSION_DEFINE_STRUCT_INLINE_ITERATOR_IMPL_IMPL( \
324 BOOST_PP_DEC(BOOST_PP_SEQ_SIZE((0)ATTRIBUTES_SEQ)))
326 #define BOOST_FUSION_DEFINE_STRUCT_INLINE_ITERATOR_IMPL_IMPL( \
327 NAME, ATTRIBUTES_SEQ, ATTRIBUTES_SEQ_SIZE) \
329 template <typename boost_fusion_detail_Seq, int N> \
330 struct BOOST_FUSION_ITERATOR_NAME(NAME) \
331 : boost::fusion::iterator_facade< \
332 BOOST_FUSION_ITERATOR_NAME(NAME)<boost_fusion_detail_Seq, N>, \
333 boost::fusion::random_access_traversal_tag \
336 typedef boost::mpl::int_<N> index; \
337 typedef boost_fusion_detail_Seq sequence_type; \
339 BOOST_FUSION_GPU_ENABLED \
340 BOOST_FUSION_ITERATOR_NAME(NAME)(boost_fusion_detail_Seq& seq) \
342 BOOST_FUSION_DEFINE_ITERATOR_WKND_INIT_LIST_ENTRIES( \
346 boost_fusion_detail_Seq& seq_; \
348 BOOST_FUSION_DEFINE_ITERATOR_WKND_MEMBERS(ATTRIBUTES_SEQ_SIZE) \
350 BOOST_FUSION_DEFINE_ITERATOR_VALUE_OF(NAME, ATTRIBUTES_SEQ_SIZE) \
352 BOOST_FUSION_DEFINE_ITERATOR_DEREF(NAME, ATTRIBUTES_SEQ) \
354 template <typename boost_fusion_detail_It> \
357 typedef BOOST_FUSION_ITERATOR_NAME(NAME)< \
358 typename boost_fusion_detail_It::sequence_type, \
359 boost_fusion_detail_It::index::value + 1 \
362 BOOST_FUSION_GPU_ENABLED \
363 static type call(boost_fusion_detail_It const& it) \
365 return type(it.seq_); \
369 template <typename boost_fusion_detail_It> \
372 typedef BOOST_FUSION_ITERATOR_NAME(NAME)< \
373 typename boost_fusion_detail_It::sequence_type, \
374 boost_fusion_detail_It::index::value - 1 \
377 BOOST_FUSION_GPU_ENABLED \
378 static type call(boost_fusion_detail_It const& it) \
380 return type(it.seq_); \
385 typename boost_fusion_detail_It1, \
386 typename boost_fusion_detail_It2 \
390 typedef typename boost::mpl::minus< \
391 typename boost_fusion_detail_It2::index, \
392 typename boost_fusion_detail_It1::index \
395 BOOST_FUSION_GPU_ENABLED \
396 static type call(boost_fusion_detail_It1 const& /* it1 */, \
397 boost_fusion_detail_It2 const& /* it2 */) \
404 typename boost_fusion_detail_It, \
405 typename boost_fusion_detail_M \
409 typedef BOOST_FUSION_ITERATOR_NAME(NAME)< \
410 typename boost_fusion_detail_It::sequence_type, \
411 boost_fusion_detail_It::index::value \
412 + boost_fusion_detail_M::value \
415 BOOST_FUSION_GPU_ENABLED \
416 static type call(boost_fusion_detail_It const& it) \
418 return type(it.seq_); \
424 #define BOOST_FUSION_DEFINE_STRUCT_INLINE_MEMBERS_IMPL_IMPL( \
425 NAME, ATTRIBUTES_SEQ, ATTRIBUTES_SEQ_SIZE) \
427 /* Note: second BOOST_PP_IF is necessary to avoid MSVC warning when */ \
428 /* calling BOOST_FUSION_IGNORE_1 with no arguments. */ \
431 ATTRIBUTES_SEQ_SIZE, \
432 BOOST_FUSION_MAKE_DEFAULT_INIT_LIST, \
433 BOOST_FUSION_IGNORE_1) \
435 ATTRIBUTES_SEQ_SIZE, \
442 ATTRIBUTES_SEQ_SIZE, \
443 BOOST_FUSION_MAKE_COPY_CONSTRUCTOR, \
444 BOOST_FUSION_IGNORE_2) \
445 (NAME, ATTRIBUTES_SEQ) \
447 template <typename boost_fusion_detail_Seq> \
448 BOOST_FUSION_GPU_ENABLED \
449 NAME(const boost_fusion_detail_Seq& rhs) \
451 boost::fusion::copy(rhs, *this); \
454 template <typename boost_fusion_detail_Seq> \
455 BOOST_FUSION_GPU_ENABLED \
456 NAME& operator=(const boost_fusion_detail_Seq& rhs) \
458 boost::fusion::copy(rhs, *this); \
462 template <typename boost_fusion_detail_Sq> \
465 typedef BOOST_FUSION_ITERATOR_NAME(NAME)<boost_fusion_detail_Sq, 0> \
468 BOOST_FUSION_GPU_ENABLED \
469 static type call(boost_fusion_detail_Sq& sq) \
475 template <typename boost_fusion_detail_Sq> \
478 typedef BOOST_FUSION_ITERATOR_NAME(NAME)< \
479 boost_fusion_detail_Sq, \
480 ATTRIBUTES_SEQ_SIZE \
483 BOOST_FUSION_GPU_ENABLED \
484 static type call(boost_fusion_detail_Sq& sq) \
490 template <typename boost_fusion_detail_Sq> \
491 struct size : boost::mpl::int_<ATTRIBUTES_SEQ_SIZE> \
495 template <typename boost_fusion_detail_Sq> \
496 struct empty : boost::mpl::bool_<ATTRIBUTES_SEQ_SIZE == 0> \
501 typename boost_fusion_detail_Sq, \
502 typename boost_fusion_detail_N \
504 struct value_at : value_at< \
505 boost_fusion_detail_Sq, \
506 boost::mpl::int_<boost_fusion_detail_N::value> \
512 ATTRIBUTES_SEQ_SIZE, \
513 BOOST_FUSION_MAKE_VALUE_AT_SPECS, \
517 typename boost_fusion_detail_Sq, \
518 typename boost_fusion_detail_N \
521 boost_fusion_detail_Sq, \
522 boost::mpl::int_<boost_fusion_detail_N::value> \
527 BOOST_PP_SEQ_FOR_EACH_I(BOOST_FUSION_MAKE_AT_SPECS, ~, ATTRIBUTES_SEQ) \
529 BOOST_PP_SEQ_FOR_EACH_I(BOOST_FUSION_MAKE_TYPEDEF, ~, ATTRIBUTES_SEQ) \
531 BOOST_PP_SEQ_FOR_EACH_I( \
532 BOOST_FUSION_MAKE_DATA_MEMBER, \