Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: /// \file domain.hpp Chris@16: /// Contains definition of domain\<\> class template and helpers for Chris@16: /// defining domains with a generator and a grammar for controlling Chris@16: /// operator overloading. Chris@16: // Chris@16: // Copyright 2008 Eric Niebler. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_PROTO_DOMAIN_HPP_EAN_02_13_2007 Chris@16: #define BOOST_PROTO_DOMAIN_HPP_EAN_02_13_2007 Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@101: #if defined(_MSC_VER) Chris@16: # pragma warning(push) Chris@16: # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined Chris@16: #endif Chris@16: Chris@16: namespace boost { namespace proto Chris@16: { Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: struct not_a_generator Chris@16: {}; Chris@16: Chris@16: struct not_a_grammar Chris@16: {}; Chris@16: Chris@16: struct not_a_domain Chris@16: {}; Chris@16: } Chris@16: Chris@16: namespace domainns_ Chris@16: { Chris@16: /// \brief For use in defining domain tags to be used Chris@16: /// with \c proto::extends\<\>. A \e Domain associates Chris@16: /// an expression type with a \e Generator, and optionally Chris@16: /// a \e Grammar. Chris@16: /// Chris@16: /// The Generator determines how new expressions in the Chris@16: /// domain are constructed. Typically, a generator wraps Chris@16: /// all new expressions in a wrapper that imparts Chris@16: /// domain-specific behaviors to expressions within its Chris@16: /// domain. (See \c proto::extends\<\>.) Chris@16: /// Chris@16: /// The Grammar determines whether a given expression is Chris@16: /// valid within the domain, and automatically disables Chris@16: /// any operator overloads which would cause an invalid Chris@16: /// expression to be created. By default, the Grammar Chris@16: /// parameter defaults to the wildcard, \c proto::_, which Chris@16: /// makes all expressions valid within the domain. Chris@16: /// Chris@16: /// The Super declares the domain currently being defined Chris@16: /// to be a sub-domain of Super. Expressions in sub-domains Chris@16: /// can be freely combined with expressions in its super- Chris@16: /// domain (and its super-domain, etc.). Chris@16: /// Chris@16: /// Example: Chris@16: /// \code Chris@16: /// template Chris@16: /// struct MyExpr; Chris@16: /// Chris@16: /// struct MyGrammar Chris@16: /// : or_< terminal<_>, plus > Chris@16: /// {}; Chris@16: /// Chris@16: /// // Define MyDomain, in which all expressions are Chris@16: /// // wrapped in MyExpr<> and only expressions that Chris@16: /// // conform to MyGrammar are allowed. Chris@16: /// struct MyDomain Chris@16: /// : domain, MyGrammar> Chris@16: /// {}; Chris@16: /// Chris@16: /// // Use MyDomain to define MyExpr Chris@16: /// template Chris@16: /// struct MyExpr Chris@16: /// : extends, MyDomain> Chris@16: /// { Chris@16: /// // ... Chris@16: /// }; Chris@16: /// \endcode Chris@16: /// Chris@16: template< Chris@16: typename Generator // = default_generator Chris@16: , typename Grammar // = proto::_ Chris@16: , typename Super // = no_super_domain Chris@16: > Chris@16: struct domain Chris@16: : Generator Chris@16: { Chris@16: typedef Generator proto_generator; Chris@16: typedef Grammar proto_grammar; Chris@16: typedef Super proto_super_domain; Chris@16: typedef domain proto_base_domain; Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: typedef void proto_is_domain_; Chris@16: Chris@16: /// \brief A unary MonomorphicFunctionObject that turns objects into Proto Chris@16: /// expression objects in this domain. Chris@16: /// Chris@16: /// The as_expr\<\> function object turns objects into Proto expressions, if Chris@16: /// they are not already, by making them Proto terminals held by value if Chris@16: /// possible. Objects that are already Proto expressions are left alone. Chris@16: /// Chris@16: /// If wants_basic_expr\::value is true, then let \c E be \c basic_expr; Chris@16: /// otherwise, let \t E be \c expr. Given an lvalue \c t of type \c T: Chris@16: /// Chris@16: /// If \c T is not a Proto expression type the resulting terminal is Chris@16: /// calculated as follows: Chris@16: /// Chris@16: /// If \c T is a function type, an abstract type, or a type derived from Chris@16: /// \c std::ios_base, let \c A be T &. Chris@16: /// Otherwise, let \c A be the type \c T stripped of cv-qualifiers. Chris@16: /// Then, the result of applying as_expr\()(t) is Chris@16: /// Generator()(E\ \>::make(t)). Chris@16: /// Chris@16: /// If \c T is a Proto expression type and its generator type is different from Chris@16: /// \c Generator, the result is Generator()(t). Chris@16: /// Chris@16: /// Otherwise, the result is \c t converted to an (un-const) rvalue. Chris@16: /// Chris@16: template Chris@16: struct as_expr Chris@16: : detail::as_expr< Chris@16: T Chris@16: , typename detail::base_generator::type Chris@16: , wants_basic_expr::value Chris@16: > Chris@16: { Chris@16: BOOST_PROTO_CALLABLE() Chris@16: }; Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: struct as_expr Chris@16: { Chris@16: BOOST_PROTO_CALLABLE() Chris@16: typedef typename remove_const::type result_type; Chris@16: Chris@16: BOOST_FORCEINLINE Chris@16: result_type operator()(T &e) const Chris@16: { Chris@16: return e; Chris@16: } Chris@16: }; Chris@16: Chris@16: /// \brief A unary MonomorphicFunctionObject that turns objects into Proto Chris@16: /// expression objects in this domain. Chris@16: /// Chris@16: /// The as_child\<\> function object turns objects into Proto expressions, if Chris@16: /// they are not already, by making them Proto terminals held by reference. Chris@16: /// Objects that are already Proto expressions are simply returned by reference. Chris@16: /// Chris@16: /// If wants_basic_expr\::value is true, then let \c E be \c basic_expr; Chris@16: /// otherwise, let \t E be \c expr. Given an lvalue \c t of type \c T: Chris@16: /// Chris@16: /// If \c T is not a Proto expression type the resulting terminal is Chris@16: /// Generator()(E\ \>::make(t)). Chris@16: /// Chris@16: /// If \c T is a Proto expression type and its generator type is different from Chris@16: /// \c Generator, the result is Generator()(t). Chris@16: /// Chris@16: /// Otherwise, the result is the lvalue \c t. Chris@16: /// Chris@16: template Chris@16: struct as_child Chris@16: : detail::as_child< Chris@16: T Chris@16: , typename detail::base_generator::type Chris@16: , wants_basic_expr::value Chris@16: > Chris@16: { Chris@16: BOOST_PROTO_CALLABLE() Chris@16: }; Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: struct as_child Chris@16: { Chris@16: BOOST_PROTO_CALLABLE() Chris@16: typedef T &result_type; Chris@16: Chris@16: BOOST_FORCEINLINE Chris@16: result_type operator()(T &e) const Chris@16: { Chris@16: return e; Chris@16: } Chris@16: }; Chris@16: }; Chris@16: Chris@16: /// \brief The domain expressions have by default, if Chris@16: /// \c proto::extends\<\> has not been used to associate Chris@16: /// a domain with an expression. Chris@16: /// Chris@16: struct default_domain Chris@16: : domain<> Chris@16: {}; Chris@16: Chris@16: /// \brief A domain to use when you prefer the use of Chris@16: /// \c proto::basic_expr\<\> over \c proto::expr\<\>. Chris@16: /// Chris@16: struct basic_default_domain Chris@16: : domain Chris@16: {}; Chris@16: Chris@16: /// \brief A pseudo-domain for use in functions and Chris@16: /// metafunctions that require a domain parameter. It Chris@16: /// indicates that the domain of the parent node should Chris@16: /// be inferred from the domains of the child nodes. Chris@16: /// Chris@16: /// \attention \c deduce_domain is not itself a valid domain. Chris@16: /// Chris@16: struct deduce_domain Chris@16: : domain Chris@16: {}; Chris@16: Chris@16: /// \brief Given a domain, a tag type and an argument list, Chris@16: /// compute the type of the expression to generate. This is Chris@16: /// either an instance of \c proto::expr\<\> or Chris@16: /// \c proto::basic_expr\<\>. Chris@16: /// Chris@16: template Chris@16: struct base_expr Chris@16: { Chris@16: typedef proto::expr type; Chris@16: }; Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: struct base_expr Chris@16: { Chris@16: typedef proto::basic_expr type; Chris@16: }; Chris@16: Chris@16: } Chris@16: Chris@16: /// A metafunction that returns \c mpl::true_ Chris@16: /// if the type \c T is the type of a Proto domain; Chris@16: /// \c mpl::false_ otherwise. If \c T inherits from Chris@16: /// \c proto::domain\<\>, \c is_domain\ is Chris@16: /// \c mpl::true_. Chris@16: template Chris@16: struct is_domain Chris@16: : mpl::false_ Chris@16: {}; Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: struct is_domain Chris@16: : mpl::true_ Chris@16: {}; Chris@16: Chris@16: /// A metafunction that returns the domain of Chris@16: /// a given type. If \c T is a Proto expression Chris@16: /// type, it returns that expression's associated Chris@16: /// domain. If not, it returns Chris@16: /// \c proto::default_domain. Chris@16: template Chris@16: struct domain_of Chris@16: { Chris@16: typedef default_domain type; Chris@16: }; Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: struct domain_of Chris@16: { Chris@16: typedef typename T::proto_domain type; Chris@16: }; Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: struct domain_of Chris@16: { Chris@16: typedef typename domain_of::type type; Chris@16: }; Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: struct domain_of, void> Chris@16: { Chris@16: typedef typename domain_of::type type; Chris@16: }; Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: struct domain_of const, void> Chris@16: { Chris@16: typedef typename domain_of::type type; Chris@16: }; Chris@16: Chris@16: /// A metafunction that returns \c mpl::true_ Chris@16: /// if the type \c SubDomain is a sub-domain of Chris@16: /// \c SuperDomain; \c mpl::false_ otherwise. Chris@16: template Chris@16: struct is_sub_domain_of Chris@16: : is_sub_domain_of Chris@16: {}; Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: struct is_sub_domain_of Chris@16: : mpl::false_ Chris@16: {}; Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: struct is_sub_domain_of Chris@16: : mpl::true_ Chris@16: {}; Chris@16: Chris@16: }} Chris@16: Chris@101: #if defined(_MSC_VER) Chris@16: # pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: #endif