1 /////////////////////////////////////////////////////////////////////////////// 2 /// \file domain.hpp 3 /// Contains definition of domain\<\> class template and helpers for 4 /// defining domains with a generator and a grammar for controlling 5 /// operator overloading. 6 // 7 // Copyright 2008 Eric Niebler. Distributed under the Boost 8 // Software License, Version 1.0. (See accompanying file 9 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 11 #ifndef BOOST_PROTO_DOMAIN_HPP_EAN_02_13_2007 12 #define BOOST_PROTO_DOMAIN_HPP_EAN_02_13_2007 13 14 #include <boost/ref.hpp> 15 #include <boost/type_traits/is_same.hpp> 16 #include <boost/proto/proto_fwd.hpp> 17 #include <boost/proto/generate.hpp> 18 #include <boost/proto/detail/as_expr.hpp> 19 #include <boost/proto/detail/deduce_domain.hpp> 20 21 #if defined(_MSC_VER) 22 # pragma warning(push) 23 # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined 24 #endif 25 26 namespace boost { namespace proto 27 { 28 29 namespace detail 30 { 31 struct not_a_generator 32 {}; 33 34 struct not_a_grammar 35 {}; 36 37 struct not_a_domain 38 {}; 39 } 40 41 namespace domainns_ 42 { 43 /// \brief For use in defining domain tags to be used 44 /// with \c proto::extends\<\>. A \e Domain associates 45 /// an expression type with a \e Generator, and optionally 46 /// a \e Grammar. 47 /// 48 /// The Generator determines how new expressions in the 49 /// domain are constructed. Typically, a generator wraps 50 /// all new expressions in a wrapper that imparts 51 /// domain-specific behaviors to expressions within its 52 /// domain. (See \c proto::extends\<\>.) 53 /// 54 /// The Grammar determines whether a given expression is 55 /// valid within the domain, and automatically disables 56 /// any operator overloads which would cause an invalid 57 /// expression to be created. By default, the Grammar 58 /// parameter defaults to the wildcard, \c proto::_, which 59 /// makes all expressions valid within the domain. 60 /// 61 /// The Super declares the domain currently being defined 62 /// to be a sub-domain of Super. Expressions in sub-domains 63 /// can be freely combined with expressions in its super- 64 /// domain (and <I>its</I> super-domain, etc.). 65 /// 66 /// Example: 67 /// \code 68 /// template<typename Expr> 69 /// struct MyExpr; 70 /// 71 /// struct MyGrammar 72 /// : or_< terminal<_>, plus<MyGrammar, MyGrammar> > 73 /// {}; 74 /// 75 /// // Define MyDomain, in which all expressions are 76 /// // wrapped in MyExpr<> and only expressions that 77 /// // conform to MyGrammar are allowed. 78 /// struct MyDomain 79 /// : domain<generator<MyExpr>, MyGrammar> 80 /// {}; 81 /// 82 /// // Use MyDomain to define MyExpr 83 /// template<typename Expr> 84 /// struct MyExpr 85 /// : extends<Expr, MyExpr<Expr>, MyDomain> 86 /// { 87 /// // ... 88 /// }; 89 /// \endcode 90 /// 91 template< 92 typename Generator // = default_generator 93 , typename Grammar // = proto::_ 94 , typename Super // = no_super_domain 95 > 96 struct domain 97 : Generator 98 { 99 typedef Generator proto_generator; 100 typedef Grammar proto_grammar; 101 typedef Super proto_super_domain; 102 typedef domain proto_base_domain; 103 104 /// INTERNAL ONLY 105 typedef void proto_is_domain_; 106 107 /// \brief A unary MonomorphicFunctionObject that turns objects into Proto 108 /// expression objects in this domain. 109 /// 110 /// The <tt>as_expr\<\></tt> function object turns objects into Proto expressions, if 111 /// they are not already, by making them Proto terminals held by value if 112 /// possible. Objects that are already Proto expressions are left alone. 113 /// 114 /// If <tt>wants_basic_expr\<Generator\>::value</tt> is true, then let \c E be \c basic_expr; 115 /// otherwise, let \t E be \c expr. Given an lvalue \c t of type \c T: 116 /// 117 /// If \c T is not a Proto expression type the resulting terminal is 118 /// calculated as follows: 119 /// 120 /// If \c T is a function type, an abstract type, or a type derived from 121 /// \c std::ios_base, let \c A be <tt>T &</tt>. 122 /// Otherwise, let \c A be the type \c T stripped of cv-qualifiers. 123 /// Then, the result of applying <tt>as_expr\<T\>()(t)</tt> is 124 /// <tt>Generator()(E\<tag::terminal, term\<A\> \>::make(t))</tt>. 125 /// 126 /// If \c T is a Proto expression type and its generator type is different from 127 /// \c Generator, the result is <tt>Generator()(t)</tt>. 128 /// 129 /// Otherwise, the result is \c t converted to an (un-const) rvalue. 130 /// 131 template<typename T, typename IsExpr = void, typename Callable = proto::callable> 132 struct as_expr 133 : detail::as_expr< 134 T 135 , typename detail::base_generator<Generator>::type 136 , wants_basic_expr<Generator>::value 137 > 138 { 139 BOOST_PROTO_CALLABLE() 140 }; 141 142 /// INTERNAL ONLY 143 /// 144 template<typename T> 145 struct as_expr<T, typename T::proto_is_expr_, proto::callable> 146 { 147 BOOST_PROTO_CALLABLE() 148 typedef typename remove_const<T>::type result_type; 149 150 BOOST_FORCEINLINE operator ()boost::proto::domainns_::domain::as_expr151 result_type operator()(T &e) const 152 { 153 return e; 154 } 155 }; 156 157 /// \brief A unary MonomorphicFunctionObject that turns objects into Proto 158 /// expression objects in this domain. 159 /// 160 /// The <tt>as_child\<\></tt> function object turns objects into Proto expressions, if 161 /// they are not already, by making them Proto terminals held by reference. 162 /// Objects that are already Proto expressions are simply returned by reference. 163 /// 164 /// If <tt>wants_basic_expr\<Generator\>::value</tt> is true, then let \c E be \c basic_expr; 165 /// otherwise, let \t E be \c expr. Given an lvalue \c t of type \c T: 166 /// 167 /// If \c T is not a Proto expression type the resulting terminal is 168 /// <tt>Generator()(E\<tag::terminal, term\<T &\> \>::make(t))</tt>. 169 /// 170 /// If \c T is a Proto expression type and its generator type is different from 171 /// \c Generator, the result is <tt>Generator()(t)</tt>. 172 /// 173 /// Otherwise, the result is the lvalue \c t. 174 /// 175 template<typename T, typename IsExpr = void, typename Callable = proto::callable> 176 struct as_child 177 : detail::as_child< 178 T 179 , typename detail::base_generator<Generator>::type 180 , wants_basic_expr<Generator>::value 181 > 182 { 183 BOOST_PROTO_CALLABLE() 184 }; 185 186 /// INTERNAL ONLY 187 /// 188 template<typename T> 189 struct as_child<T, typename T::proto_is_expr_, proto::callable> 190 { 191 BOOST_PROTO_CALLABLE() 192 typedef T &result_type; 193 194 BOOST_FORCEINLINE operator ()boost::proto::domainns_::domain::as_child195 result_type operator()(T &e) const 196 { 197 return e; 198 } 199 }; 200 }; 201 202 /// \brief The domain expressions have by default, if 203 /// \c proto::extends\<\> has not been used to associate 204 /// a domain with an expression. 205 /// 206 struct default_domain 207 : domain<> 208 {}; 209 210 /// \brief A domain to use when you prefer the use of 211 /// \c proto::basic_expr\<\> over \c proto::expr\<\>. 212 /// 213 struct basic_default_domain 214 : domain<basic_default_generator> 215 {}; 216 217 /// \brief A pseudo-domain for use in functions and 218 /// metafunctions that require a domain parameter. It 219 /// indicates that the domain of the parent node should 220 /// be inferred from the domains of the child nodes. 221 /// 222 /// \attention \c deduce_domain is not itself a valid domain. 223 /// 224 struct deduce_domain 225 : domain<detail::not_a_generator, detail::not_a_grammar, detail::not_a_domain> 226 {}; 227 228 /// \brief Given a domain, a tag type and an argument list, 229 /// compute the type of the expression to generate. This is 230 /// either an instance of \c proto::expr\<\> or 231 /// \c proto::basic_expr\<\>. 232 /// 233 template<typename Domain, typename Tag, typename Args, bool WantsBasicExpr> 234 struct base_expr 235 { 236 typedef proto::expr<Tag, Args, Args::arity> type; 237 }; 238 239 /// INTERNAL ONLY 240 /// 241 template<typename Domain, typename Tag, typename Args> 242 struct base_expr<Domain, Tag, Args, true> 243 { 244 typedef proto::basic_expr<Tag, Args, Args::arity> type; 245 }; 246 247 } 248 249 /// A metafunction that returns \c mpl::true_ 250 /// if the type \c T is the type of a Proto domain; 251 /// \c mpl::false_ otherwise. If \c T inherits from 252 /// \c proto::domain\<\>, \c is_domain\<T\> is 253 /// \c mpl::true_. 254 template<typename T, typename Void /* = void*/> 255 struct is_domain 256 : mpl::false_ 257 {}; 258 259 /// INTERNAL ONLY 260 /// 261 template<typename T> 262 struct is_domain<T, typename T::proto_is_domain_> 263 : mpl::true_ 264 {}; 265 266 /// A metafunction that returns the domain of 267 /// a given type. If \c T is a Proto expression 268 /// type, it returns that expression's associated 269 /// domain. If not, it returns 270 /// \c proto::default_domain. 271 template<typename T, typename Void /* = void*/> 272 struct domain_of 273 { 274 typedef default_domain type; 275 }; 276 277 /// INTERNAL ONLY 278 /// 279 template<typename T> 280 struct domain_of<T, typename T::proto_is_expr_> 281 { 282 typedef typename T::proto_domain type; 283 }; 284 285 /// INTERNAL ONLY 286 /// 287 template<typename T> 288 struct domain_of<T &, void> 289 { 290 typedef typename domain_of<T>::type type; 291 }; 292 293 /// INTERNAL ONLY 294 /// 295 template<typename T> 296 struct domain_of<boost::reference_wrapper<T>, void> 297 { 298 typedef typename domain_of<T>::type type; 299 }; 300 301 /// INTERNAL ONLY 302 /// 303 template<typename T> 304 struct domain_of<boost::reference_wrapper<T> const, void> 305 { 306 typedef typename domain_of<T>::type type; 307 }; 308 309 /// A metafunction that returns \c mpl::true_ 310 /// if the type \c SubDomain is a sub-domain of 311 /// \c SuperDomain; \c mpl::false_ otherwise. 312 template<typename SubDomain, typename SuperDomain> 313 struct is_sub_domain_of 314 : is_sub_domain_of<typename SubDomain::proto_super_domain, SuperDomain> 315 {}; 316 317 /// INTERNAL ONLY 318 /// 319 template<typename SuperDomain> 320 struct is_sub_domain_of<proto::no_super_domain, SuperDomain> 321 : mpl::false_ 322 {}; 323 324 /// INTERNAL ONLY 325 /// 326 template<typename SuperDomain> 327 struct is_sub_domain_of<SuperDomain, SuperDomain> 328 : mpl::true_ 329 {}; 330 331 }} 332 333 #if defined(_MSC_VER) 334 # pragma warning(pop) 335 #endif 336 337 #endif 338