blob: 06c414b94685433385d95b840cd6e08db3b31865 [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
/// \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 <boost/proto/detail/prefix.hpp>
#include <boost/ref.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/proto/proto_fwd.hpp>
#include <boost/proto/generate.hpp>
#include <boost/proto/detail/suffix.hpp>
namespace boost { namespace proto
{
namespace detail
{
struct not_a_generator
{};
struct not_a_grammar
{};
}
BOOST_PROTO_BEGIN_ADL_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.
///
/// Example:
/// \code
/// template<typename Expr>
/// struct MyExpr;
///
/// struct MyGrammar
/// : or_< terminal<_>, plus<MyGrammar, MyGrammar> >
/// {};
///
/// // Define MyDomain, in which all expressions are
/// // wrapped in MyExpr<> and only expressions that
/// // conform to MyGrammar are allowed.
/// struct MyDomain
/// : domain<generator<MyExpr>, MyGrammar>
/// {};
///
/// // Use MyDomain to define MyExpr
/// template<typename Expr>
/// struct MyExpr
/// : extends<Expr, MyExpr<Expr>, MyDomain>
/// {
/// // ...
/// };
/// \endcode
///
template<
typename Generator BOOST_PROTO_WHEN_BUILDING_DOCS(= default_generator)
, typename Grammar BOOST_PROTO_WHEN_BUILDING_DOCS(= proto::_)
>
struct domain
: Generator
{
typedef Grammar proto_grammar;
/// INTERNAL ONLY
typedef void proto_is_domain_;
};
/// \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 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<detail::not_a_generator, detail::not_a_grammar>
{};
BOOST_PROTO_END_ADL_NAMESPACE(domainns_)
namespace result_of
{
/// 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\<T\> is
/// \c mpl::true_.
template<typename T, typename Void BOOST_PROTO_WHEN_BUILDING_DOCS(= void)>
struct is_domain
: mpl::false_
{};
/// INTERNAL ONLY
///
template<typename T>
struct is_domain<T, typename T::proto_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<typename T, typename Void BOOST_PROTO_WHEN_BUILDING_DOCS(= void)>
struct domain_of
{
typedef default_domain type;
};
/// INTERNAL ONLY
///
template<typename T>
struct domain_of<T, typename T::proto_is_expr_>
{
typedef typename T::proto_domain type;
};
/// INTERNAL ONLY
///
template<typename T>
struct domain_of<T &, void>
{
typedef typename domain_of<T>::type type;
};
/// INTERNAL ONLY
///
template<typename T>
struct domain_of<boost::reference_wrapper<T>, void>
{
typedef typename domain_of<T>::type type;
};
/// INTERNAL ONLY
///
template<typename T>
struct domain_of<boost::reference_wrapper<T> const, void>
{
typedef typename domain_of<T>::type type;
};
}
}}
#endif