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/proto/make_expr.hpp> 17 #include <boost/proto/traits.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 operator ()boost::spirit::detail::nary_proto_expr_function96 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 operator ()boost::spirit::detail::nary_proto_expr_function104 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 operator ()boost::spirit::detail::nary_proto_expr_function145 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 operator ()boost::spirit::detail::nary_proto_expr_function153 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 callboost::spirit::make_unary_proto_expr173 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 callboost::spirit::make_nary_proto_expr190 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 213