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