1 /*============================================================================= 2 Copyright (c) 2001-2011 Joel de Guzman 3 Copyright (c) 2001-2011 Hartmut Kaiser 4 http://spirit.sourceforge.net/ 5 6 Distributed under the Boost Software License, Version 1.0. (See accompanying 7 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 =============================================================================*/ 9 #if !defined(BOOST_SPIRIT_ACTION_DISPATCH_APRIL_18_2008_0720AM) 10 #define BOOST_SPIRIT_ACTION_DISPATCH_APRIL_18_2008_0720AM 11 12 #if defined(_MSC_VER) 13 #pragma once 14 #endif 15 16 #include<boost/config.hpp> 17 18 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_LAMBDAS) && \ 19 !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_DECLTYPE) 20 #include <utility> 21 #include <type_traits> 22 #endif 23 24 25 #include <boost/spirit/home/support/attributes.hpp> 26 27 namespace boost { namespace phoenix 28 { 29 template <typename Expr> 30 struct actor; 31 }} 32 33 namespace boost { namespace spirit { namespace traits 34 { 35 template <typename Component> 36 struct action_dispatch 37 { 38 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_LAMBDAS) && \ 39 !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_DECLTYPE) 40 // omit function parameters without specializing for each possible 41 // type of callable entity 42 // many thanks to Eelis/##iso-c++ for this contribution 43 44 private: 45 // this will be used to pass around POD types which are safe 46 // to go through the ellipsis operator (if ever used) 47 template <typename> 48 struct fwd_tag {}; 49 50 // the first parameter is a placeholder to obtain SFINAE when 51 // doing overload resolution, the second one is the actual 52 // forwarder, where we can apply our implementation 53 template <typename, typename T> 54 struct fwd_storage { typedef T type; }; 55 56 // gcc should accept fake<T>() but it prints a sorry, needs 57 // a check once the bug is sorted out, use a FAKE_CALL macro for now 58 template <typename T> 59 T fake_call(); 60 61 #define BOOST_SPIRIT_FAKE_CALL(T) (*(T*)0) 62 63 // the forwarders, here we could tweak the implementation of 64 // how parameters are passed to the functions, if needed 65 struct fwd_none 66 { 67 template<typename F, typename... Rest> operator ()boost::spirit::traits::action_dispatch::fwd_none68 auto operator()(F && f, Rest&&...) -> decltype(f()) 69 { 70 return f(); 71 } 72 }; 73 74 struct fwd_attrib 75 { 76 template<typename F, typename A, typename... Rest> operator ()boost::spirit::traits::action_dispatch::fwd_attrib77 auto operator()(F && f, A && a, Rest&&...) -> decltype(f(a)) 78 { 79 return f(a); 80 } 81 }; 82 83 struct fwd_attrib_context 84 { 85 template<typename F, typename A, typename B, typename... Rest> operator ()boost::spirit::traits::action_dispatch::fwd_attrib_context86 auto operator()(F && f, A && a, B && b, Rest&&...) 87 -> decltype(f(a, b)) 88 { 89 return f(a, b); 90 } 91 }; 92 93 struct fwd_attrib_context_pass 94 { 95 template<typename F, typename A, typename B, typename C 96 , typename... Rest> operator ()boost::spirit::traits::action_dispatch::fwd_attrib_context_pass97 auto operator()(F && f, A && a, B && b, C && c, Rest&&...) 98 -> decltype(f(a, b, c)) 99 { 100 return f(a, b, c); 101 } 102 }; 103 104 // SFINAE for our calling syntax, the forwarders are stored based 105 // on what function call gives a proper result 106 // this code can probably be more generic once implementations are 107 // steady 108 template <typename F> do_callboost::spirit::traits::action_dispatch109 static auto do_call(F && f, ...) 110 -> typename fwd_storage<decltype(f()), fwd_none>::type 111 { 112 return {}; 113 } 114 115 template <typename F, typename A> do_callboost::spirit::traits::action_dispatch116 static auto do_call(F && f, fwd_tag<A>, ...) 117 -> typename fwd_storage<decltype(f(BOOST_SPIRIT_FAKE_CALL(A))) 118 , fwd_attrib>::type 119 { 120 return {}; 121 } 122 123 template <typename F, typename A, typename B> do_callboost::spirit::traits::action_dispatch124 static auto do_call(F && f, fwd_tag<A>, fwd_tag<B>, ...) 125 -> typename fwd_storage< 126 decltype(f(BOOST_SPIRIT_FAKE_CALL(A), BOOST_SPIRIT_FAKE_CALL(B))) 127 , fwd_attrib_context>::type 128 { 129 return {}; 130 } 131 132 template <typename F, typename A, typename B, typename C> do_callboost::spirit::traits::action_dispatch133 static auto do_call(F && f, fwd_tag<A>, fwd_tag<B>, fwd_tag<C>, ...) 134 -> typename fwd_storage< 135 decltype(f(BOOST_SPIRIT_FAKE_CALL(A), BOOST_SPIRIT_FAKE_CALL(B) 136 , BOOST_SPIRIT_FAKE_CALL(C))) 137 , fwd_attrib_context_pass>::type 138 { 139 return {}; 140 } 141 142 // this function calls the forwarder and is responsible for 143 // stripping the tail of the parameters 144 template <typename F, typename... A> callerboost::spirit::traits::action_dispatch145 static void caller(F && f, A && ... a) 146 { 147 do_call(f, fwd_tag<typename std::remove_reference<A>::type>()...) 148 (std::forward<F>(f), std::forward<A>(a)...); 149 } 150 151 #undef BOOST_SPIRIT_FAKE_CALL 152 153 public: 154 template <typename F, typename Attribute, typename Context> operator ()boost::spirit::traits::action_dispatch155 bool operator()(F const& f, Attribute& attr, Context& context) 156 { 157 bool pass = true; 158 caller(f, attr, context, pass); 159 return pass; 160 } 161 #else 162 // general handler for everything not explicitly specialized below 163 template <typename F, typename Attribute, typename Context> 164 bool operator()(F const& f, Attribute& attr, Context& context) 165 { 166 bool pass = true; 167 f(attr, context, pass); 168 return pass; 169 } 170 #endif 171 172 // handler for phoenix actors 173 174 // If the component this action has to be invoked for is a tuple, we 175 // wrap any non-fusion tuple into a fusion tuple (done by pass_attribute) 176 // and pass through any fusion tuple. 177 template <typename Eval, typename Attribute, typename Context> operator ()boost::spirit::traits::action_dispatch178 bool operator()(phoenix::actor<Eval> const& f 179 , Attribute& attr, Context& context) 180 { 181 bool pass = true; 182 typename pass_attribute<Component, Attribute>::type attr_wrap(attr); 183 f(attr_wrap, context, pass); 184 return pass; 185 } 186 187 // specializations for plain function pointers taking different number of 188 // arguments 189 template <typename RT, typename A0, typename A1, typename A2 190 , typename Attribute, typename Context> operator ()boost::spirit::traits::action_dispatch191 bool operator()(RT(*f)(A0, A1, A2), Attribute& attr, Context& context) 192 { 193 bool pass = true; 194 f(attr, context, pass); 195 return pass; 196 } 197 198 template <typename RT, typename A0, typename A1 199 , typename Attribute, typename Context> operator ()boost::spirit::traits::action_dispatch200 bool operator()(RT(*f)(A0, A1), Attribute& attr, Context& context) 201 { 202 f(attr, context); 203 return true; 204 } 205 206 template <typename RT, typename A0, typename Attribute, typename Context> operator ()boost::spirit::traits::action_dispatch207 bool operator()(RT(*f)(A0), Attribute& attr, Context&) 208 { 209 f(attr); 210 return true; 211 } 212 213 template <typename RT, typename Attribute, typename Context> operator ()boost::spirit::traits::action_dispatch214 bool operator()(RT(*f)(), Attribute&, Context&) 215 { 216 f(); 217 return true; 218 } 219 }; 220 }}} 221 222 #endif 223