// Copyright David Abrahams, Daniel Wallin 2003. Use, modification and // distribution is subject to 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_PARAMETERS_031014_HPP #define BOOST_PARAMETERS_031014_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace parameter_ { template struct unmatched_argument { BOOST_MPL_ASSERT((boost::is_same)); typedef int type; }; } // namespace parameter_ namespace boost { template class reference_wrapper; namespace parameter { namespace aux { struct use_default {}; } // These templates can be used to describe the treatment of particular // named parameters for the purposes of overload elimination with // SFINAE, by placing specializations in the parameters<...> list. In // order for a treated function to participate in overload resolution: // // - all keyword tags wrapped in required<...> must have a matching // actual argument // // - The actual argument type matched by every keyword tag // associated with a predicate must satisfy that predicate // // If a keyword k is specified without an optional<...> or // required<...>, wrapper, it is treated as though optional were // specified. // // If a keyword k is specified with deduced<...>, that keyword // will be automatically deduced from the argument list. // template struct required { typedef Tag key_type; typedef Predicate predicate; }; template struct optional { typedef Tag key_type; typedef Predicate predicate; }; template struct deduced { typedef Tag key_type; }; namespace aux { // Defines metafunctions, is_required and is_optional, that // identify required<...>, optional<...> and deduced<...> specializations. BOOST_DETAIL_IS_XXX_DEF(required, required, 2) BOOST_DETAIL_IS_XXX_DEF(optional, optional, 2) BOOST_DETAIL_IS_XXX_DEF(deduced_aux, deduced, 1) template struct is_deduced0 : is_deduced_aux< typename S::key_type >::type {}; template struct is_deduced : mpl::eval_if< mpl::or_< is_optional, is_required > , is_deduced0 , mpl::false_ >::type {}; // // key_type, has_default, and predicate -- // // These metafunctions accept a ParameterSpec and extract the // keyword tag, whether or not a default is supplied for the // parameter, and the predicate that the corresponding actual // argument type is required match. // // a ParameterSpec is a specialization of either keyword<...>, // required<...>, optional<...> // // helper for key_type<...>, below. template struct get_tag_type0 { typedef typename T::key_type type; }; template struct get_tag_type : mpl::eval_if< is_deduced_aux , get_tag_type0 , mpl::identity > {}; template struct tag_type : mpl::eval_if< mpl::or_< is_optional , is_required > , get_tag_type , mpl::identity > {}; template struct has_default : mpl::not_ > {}; // helper for get_predicate<...>, below template struct get_predicate_or_default { typedef T type; }; template <> struct get_predicate_or_default { typedef mpl::always type; }; // helper for predicate<...>, below template struct get_predicate { typedef typename get_predicate_or_default::type type; }; template struct predicate : mpl::eval_if< mpl::or_< is_optional , is_required > , get_predicate , mpl::identity > > { }; // Converts a ParameterSpec into a specialization of // parameter_requirements. We need to do this in order to get the // tag_type into the type in a way that can be conveniently matched // by a satisfies(...) member function in arg_list. template struct as_parameter_requirements { typedef parameter_requirements< typename tag_type::type , typename predicate::type , typename has_default::type > type; }; template struct is_named_argument : mpl::or_< is_template_keyword , is_tagged_argument > {}; // Returns mpl::true_ iff the given ParameterRequirements are // satisfied by ArgList. template struct satisfies { #if BOOST_WORKAROUND(BOOST_MSVC, == 1310) // VC7.1 can't handle the sizeof() implementation below, // so we use this instead. typedef typename mpl::apply_wrap3< typename ArgList::binding , typename ParameterRequirements::keyword , void_ , mpl::false_ >::type bound; typedef typename mpl::eval_if< is_same , typename ParameterRequirements::has_default , mpl::apply_wrap2< typename mpl::lambda< typename ParameterRequirements::predicate, lambda_tag >::type , bound , ArgList > >::type type; #else BOOST_STATIC_CONSTANT( bool, value = ( sizeof( aux::to_yesno( ArgList::satisfies((ParameterRequirements*)0, (ArgList*)0) ) ) == sizeof(yes_tag) ) ); typedef mpl::bool_ type; #endif }; // Returns mpl::true_ if the requirements of the given ParameterSpec // are satisfied by ArgList. template struct satisfies_requirements_of : satisfies< ArgList , typename as_parameter_requirements::type > {}; // Tags a deduced argument Arg with the keyword tag of Spec using TagFn. // Returns the tagged argument and the mpl::set<> UsedArgs with the // tag of Spec inserted. template struct tag_deduced { typedef mpl::pair< typename mpl::apply_wrap2::type, Arg>::type , typename aux::insert_::type>::type > type; }; template < class Argument , class ArgumentPack , class DeducedArgs , class UsedArgs , class TagFn > struct deduce_tag; // Tag type passed to MPL lambda. struct lambda_tag; // Helper for deduce_tag<> below. template < class Argument , class ArgumentPack , class DeducedArgs , class UsedArgs , class TagFn > struct deduce_tag0 { typedef typename DeducedArgs::spec spec; typedef typename mpl::apply_wrap2< typename mpl::lambda< typename spec::predicate, lambda_tag >::type , Argument , ArgumentPack >::type condition; // Deduced parameter matches several arguments. BOOST_MPL_ASSERT(( mpl::not_::type> > > )); typedef typename mpl::eval_if< condition , tag_deduced , deduce_tag >::type type; }; // Tries to deduced a keyword tag for a given Argument. // Returns an mpl::pair<> consisting of the tagged_argument<>, // and an mpl::set<> where the new tag has been inserted. // // Argument: The argument type to be tagged. // // ArgumentPack: The ArgumentPack built so far. // // DeducedArgs: A specialization of deduced_item<> (see below). // A list containing only the deduced ParameterSpecs. // // UsedArgs: An mpl::set<> containing the keyword tags used so far. // // TagFn: A metafunction class used to tag positional or deduced // arguments with a keyword tag. template < class Argument , class ArgumentPack , class DeducedArgs , class UsedArgs , class TagFn > struct deduce_tag { typedef typename mpl::eval_if< is_same , mpl::pair , deduce_tag0 >::type type; }; template < class List , class DeducedArgs , class TagFn , class Positional , class UsedArgs , class ArgumentPack , class Error > struct make_arg_list_aux; // Inserts Tagged::key_type into the UserArgs set. // Extra indirection to lazily evaluate Tagged::key_type. template struct insert_tagged { typedef typename aux::insert_< UsedArgs, typename Tagged::key_type >::type type; }; // Borland needs the insane extra-indirection workaround below // so that it doesn't magically drop the const qualifier from // the argument type. template < class List , class DeducedArgs , class TagFn , class Positional , class UsedArgs , class ArgumentPack #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) , class argument #endif , class Error > #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) struct make_arg_list00 #else struct make_arg_list0 #endif { #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) typedef typename List::arg argument; #endif typedef typename List::spec parameter_spec; typedef typename tag_type::type tag_; typedef is_named_argument is_tagged; // If this argument is either explicitly tagged or a deduced // parameter, we turn off positional matching. typedef mpl::and_< mpl::not_< mpl::or_, is_tagged> > , Positional > positional; // If this parameter is explicitly tagged we add it to the // used-parmeters set. We only really need to add parameters // that are deduced, but we would need a way to check if // a given tag corresponds to a deduced parameter spec. typedef typename mpl::eval_if< is_tagged , insert_tagged , mpl::identity >::type used_args; // If this parameter is neither explicitly tagged, nor // positionally matched; deduce the tag from the deduced // parameter specs. typedef typename mpl::eval_if< mpl::or_ , mpl::pair , deduce_tag >::type deduced_data; // If this parameter is explicitly tagged.. typedef typename mpl::eval_if< is_tagged , mpl::identity // .. just use it , mpl::eval_if< // .. else, if positional matching is turned on.. positional , mpl::apply_wrap2 // .. tag it positionally , mpl::first // .. else, use the deduced tag > >::type tagged; // We build the arg_list incrementally as we go, prepending new // nodes. typedef typename mpl::if_< mpl::and_< is_same , is_same > , parameter_::unmatched_argument , void_ >::type error; typedef typename mpl::if_< is_same , ArgumentPack , arg_list >::type argument_pack; typedef typename make_arg_list_aux< typename List::tail , DeducedArgs , TagFn , positional , typename deduced_data::second , argument_pack , error >::type type; }; #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) template < class List , class DeducedArgs , class TagFn , class Positional , class UsedArgs , class ArgumentPack , class Error > struct make_arg_list0 { typedef typename mpl::eval_if< typename List::is_arg_const , make_arg_list00< List , DeducedArgs , TagFn , Positional , UsedArgs , ArgumentPack , typename List::arg const , Error > , make_arg_list00< List , DeducedArgs , TagFn , Positional , UsedArgs , ArgumentPack , typename List::arg , Error > >::type type; }; #endif // Returns an ArgumentPack where the list of arguments has // been tagged with keyword tags. // // List: A specialization of item<> (see below). Contains // both the ordered ParameterSpecs, and the given arguments. // // DeducedArgs: A specialization of deduced_item<> (see below). // A list containing only the deduced ParameterSpecs. // // TagFn: A metafunction class used to tag positional or deduced // arguments with a keyword tag. // // Position: An mpl::bool_<> specialization indicating if positional // matching is to be performed. // // DeducedSet: An mpl::set<> containing the keyword tags used so far. // // ArgumentPack: The ArgumentPack built so far. This is initially an // empty_arg_list and is built incrementally. // template < class List , class DeducedArgs , class TagFn , class Positional , class DeducedSet , class ArgumentPack , class Error > struct make_arg_list_aux { typedef typename mpl::eval_if< is_same , mpl::identity > , make_arg_list0 >::type type; }; // VC6.5 was choking on the default parameters for make_arg_list_aux, so // this just forwards to that adding in the defaults. template < class List , class DeducedArgs , class TagFn , class EmitErrors = mpl::true_ > struct make_arg_list { typedef typename make_arg_list_aux< List, DeducedArgs, TagFn, mpl::true_, aux::set0, empty_arg_list, void_ >::type type; }; // A parameter spec item typelist. template struct item { typedef Spec spec; #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) typedef is_const is_arg_const; #endif typedef Arg arg; typedef Tail tail; }; template struct make_item { typedef item type; }; // Creates a item typelist. template struct make_items { typedef typename mpl::eval_if< is_same , mpl::identity , make_item >::type type; }; // A typelist that stored deduced parameter specs. template struct deduced_item { typedef ParameterSpec spec; typedef Tail tail; }; // Evaluate Tail and construct deduced_item list. template struct make_deduced_item { typedef deduced_item type; }; template struct make_deduced_items { typedef typename mpl::eval_if< is_same , mpl::identity , mpl::eval_if< is_deduced , make_deduced_item , Tail > >::type type; }; // Generates: // // make< // parameter_spec#0, argument_type#0 // , make< // parameter_spec#1, argument_type#1 // , ... mpl::identity // ...> // > #define BOOST_PARAMETER_make_arg_list(z, n, names) \ BOOST_PP_SEQ_ELEM(0,names)< \ BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(1,names), n), \ BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(2,names), n), #define BOOST_PARAMETER_right_angle(z, n, text) > #define BOOST_PARAMETER_build_arg_list(n, make, parameter_spec, argument_type) \ BOOST_PP_REPEAT( \ n, BOOST_PARAMETER_make_arg_list, (make)(parameter_spec)(argument_type)) \ mpl::identity \ BOOST_PP_REPEAT(n, BOOST_PARAMETER_right_angle, _) #define BOOST_PARAMETER_make_deduced_list(z, n, names) \ BOOST_PP_SEQ_ELEM(0,names)< \ BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(1,names), n), #define BOOST_PARAMETER_build_deduced_list(n, make, parameter_spec) \ BOOST_PP_REPEAT( \ n, BOOST_PARAMETER_make_deduced_list, (make)(parameter_spec)) \ mpl::identity \ BOOST_PP_REPEAT(n, BOOST_PARAMETER_right_angle, _) struct tag_keyword_arg { template struct apply : tag {}; }; struct tag_template_keyword_arg { template struct apply { typedef template_keyword type; }; }; } // namespace aux #define BOOST_PARAMETER_FORWARD_TYPEDEF(z, i, names) \ typedef BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0,names),i) BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(1,names),i); #define BOOST_PARAMETER_FORWARD_TYPEDEFS(n, src, dest) \ BOOST_PP_REPEAT(n, BOOST_PARAMETER_FORWARD_TYPEDEF, (src)(dest)) #define BOOST_PARAMETER_TEMPLATE_ARGS(z, n, text) class BOOST_PP_CAT(PS, n) = void_ template< class PS0 , BOOST_PP_ENUM_SHIFTED(BOOST_PARAMETER_MAX_ARITY, BOOST_PARAMETER_TEMPLATE_ARGS, _) > struct parameters { #undef BOOST_PARAMETER_TEMPLATE_ARGS typedef typename BOOST_PARAMETER_build_deduced_list( BOOST_PARAMETER_MAX_ARITY, aux::make_deduced_items, PS )::type deduced_list; // if the elements of NamedList match the criteria of overload // resolution, returns a type which can be constructed from // parameters. Otherwise, this is not a valid metafunction (no nested // ::type). #ifndef BOOST_NO_SFINAE // If NamedList satisfies the PS0, PS1, ..., this is a // metafunction returning parameters. Otherwise it // has no nested ::type. template struct match_base : mpl::if_< // mpl::and_< // aux::satisfies_requirements_of // , mpl::and_< // aux::satisfies_requirements_of... // ..., mpl::true_ // ...> > # define BOOST_PARAMETER_satisfies(z, n, text) \ mpl::and_< \ aux::satisfies_requirements_of< \ typename mpl::first::type \ , BOOST_PP_CAT(PS, n)> \ , mpl::and_< is_same::type, void_> , BOOST_PP_REPEAT(BOOST_PARAMETER_MAX_ARITY, BOOST_PARAMETER_satisfies, _) mpl::true_ BOOST_PP_REPEAT(BOOST_PARAMETER_MAX_ARITY, BOOST_PARAMETER_right_angle, _) > # undef BOOST_PARAMETER_satisfies , mpl::identity , void_ > {}; #endif // Specializations are to be used as an optional argument to // eliminate overloads via SFINAE template< #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) // Borland simply can't handle default arguments in member // class templates. People wishing to write portable code can // explicitly specify BOOST_PARAMETER_MAX_ARITY arguments BOOST_PP_ENUM_PARAMS(BOOST_PARAMETER_MAX_ARITY, class A) #else BOOST_PP_ENUM_BINARY_PARAMS( BOOST_PARAMETER_MAX_ARITY, class A, = void_ BOOST_PP_INTERCEPT ) #endif > struct match # ifndef BOOST_NO_SFINAE : match_base< typename aux::make_arg_list< typename BOOST_PARAMETER_build_arg_list( BOOST_PARAMETER_MAX_ARITY, aux::make_items, PS, A )::type , deduced_list , aux::tag_keyword_arg , mpl::false_ // Don't emit errors when doing SFINAE >::type >::type {}; # else { typedef parameters< BOOST_PP_ENUM_PARAMS(BOOST_PARAMETER_MAX_ARITY, PS) > type; }; # endif // Metafunction that returns an ArgumentPack. // TODO, bind has to instantiate the error type in the result // of make_arg_list. template < #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) // Borland simply can't handle default arguments in member // class templates. People wishing to write portable code can // explicitly specify BOOST_PARAMETER_MAX_ARITY arguments BOOST_PP_ENUM_PARAMS(BOOST_PARAMETER_MAX_ARITY, class A) #else BOOST_PP_ENUM_BINARY_PARAMS( BOOST_PARAMETER_MAX_ARITY, class A, = void_ BOOST_PP_INTERCEPT ) #endif > struct bind { typedef typename aux::make_arg_list< typename BOOST_PARAMETER_build_arg_list( BOOST_PARAMETER_MAX_ARITY, aux::make_items, PS, A )::type , deduced_list , aux::tag_template_keyword_arg >::type result; typedef typename mpl::first::type type; }; BOOST_PARAMETER_FORWARD_TYPEDEFS(BOOST_PARAMETER_MAX_ARITY, PS, parameter_spec) // // The function call operator is used to build an arg_list that // labels the positional parameters and maintains whatever other // tags may have been specified by the caller. // // !!!NOTE!!! // // The make_arg_list<> produces a reversed arg_list, so // we need to pass the arguments to it's constructor // reversed. // aux::empty_arg_list operator()() const { return aux::empty_arg_list(); } template typename mpl::first< typename aux::make_arg_list< aux::item< PS0,A0 > , deduced_list , aux::tag_keyword_arg >::type >::type operator()(A0& a0) const { typedef typename aux::make_arg_list< aux::item< PS0,A0 > , deduced_list , aux::tag_keyword_arg >::type result; typedef typename mpl::first::type result_type; typedef typename mpl::second::type error; error(); return result_type( a0 // , void_(), void_(), void_() ... BOOST_PP_ENUM_TRAILING_PARAMS( BOOST_PP_SUB(BOOST_PARAMETER_MAX_ARITY, 1) , aux::void_reference() BOOST_PP_INTERCEPT) ); } template typename mpl::first< typename aux::make_arg_list< aux::item< PS0,A0 , aux::item< PS1,A1 > > , deduced_list , aux::tag_keyword_arg >::type >::type operator()(A0& a0, A1& a1) const { typedef typename aux::make_arg_list< aux::item< PS0,A0 , aux::item< PS1,A1 > > , deduced_list , aux::tag_keyword_arg >::type result; typedef typename mpl::first::type result_type; typedef typename mpl::second::type error; error(); return result_type( a1,a0 // , void_(), void_() ... BOOST_PP_ENUM_TRAILING_PARAMS( BOOST_PP_SUB(BOOST_PARAMETER_MAX_ARITY, 2) , aux::void_reference() BOOST_PP_INTERCEPT) ); } // Higher arities are handled by the preprocessor #define BOOST_PP_ITERATION_PARAMS_1 (3,( \ 3,BOOST_PARAMETER_MAX_ARITY, \ )) #include BOOST_PP_ITERATE() }; } // namespace parameter } // namespace boost #endif // BOOST_PARAMETERS_031014_HPP