// 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 <boost/detail/is_xxx.hpp>

#include <boost/type_traits/is_const.hpp>

#include <boost/mpl/lambda.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/always.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/pair.hpp>

#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/remove_reference.hpp>

#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/repetition/enum_shifted.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/preprocessor/facilities/intercept.hpp>
#include <boost/preprocessor/cat.hpp>

#include <boost/parameter/aux_/arg_list.hpp>
#include <boost/parameter/aux_/yesno.hpp>
#include <boost/parameter/aux_/void.hpp>
#include <boost/parameter/aux_/default.hpp>
#include <boost/parameter/aux_/unwrap_cv_reference.hpp>
#include <boost/parameter/aux_/tagged_argument.hpp>
#include <boost/parameter/aux_/tag.hpp>
#include <boost/parameter/aux_/template_keyword.hpp>
#include <boost/parameter/aux_/set.hpp>
#include <boost/parameter/config.hpp>

namespace parameter_
{
  template <class T>
  struct unmatched_argument
  {
      BOOST_MPL_ASSERT((boost::is_same<T,void>));
      typedef int type;
  }; 
} // namespace parameter_

namespace boost {

template<class T> 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<k> were
// specified.
//
// If a keyword k is specified with deduced<...>, that keyword
// will be automatically deduced from the argument list.
//
template <class Tag, class Predicate = aux::use_default>
struct required
{
    typedef Tag key_type;
    typedef Predicate predicate;
};

template <class Tag, class Predicate = aux::use_default>
struct optional
{
    typedef Tag key_type;
    typedef Predicate predicate;
};

template <class Tag>
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 <class S>
  struct is_deduced0
    : is_deduced_aux<
          typename S::key_type
      >::type
  {};

  template <class S>
  struct is_deduced
    : mpl::eval_if<
          mpl::or_<
              is_optional<S>, is_required<S>
          >
        , is_deduced0<S>
        , 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 <class T>
  struct get_tag_type0
  {
      typedef typename T::key_type type;
  };

  template <class T>
  struct get_tag_type
    : mpl::eval_if<
          is_deduced_aux<typename T::key_type>
        , get_tag_type0<typename T::key_type>
        , mpl::identity<typename T::key_type>
      >
  {};

  template <class T>
  struct tag_type
    : mpl::eval_if<
          mpl::or_<
              is_optional<T>
            , is_required<T>
          >
        , get_tag_type<T>
        , mpl::identity<T>
      >
  {};

  template <class T>
  struct has_default
    : mpl::not_<is_required<T> >
  {};

  // helper for get_predicate<...>, below
  template <class T>
  struct get_predicate_or_default
  {
      typedef T type;
  };

  template <>
  struct get_predicate_or_default<use_default>
  {
      typedef mpl::always<mpl::true_> type;
  };

  // helper for predicate<...>, below
  template <class T>
  struct get_predicate
  {
      typedef typename
          get_predicate_or_default<typename T::predicate>::type
      type;
  };

  template <class T>
  struct predicate
    : mpl::eval_if<
         mpl::or_<
              is_optional<T>
            , is_required<T>
          >
        , get_predicate<T>
        , mpl::identity<mpl::always<mpl::true_> >
      >
  {
  };


  // 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 <class ParameterSpec>
  struct as_parameter_requirements
  {
      typedef parameter_requirements<
          typename tag_type<ParameterSpec>::type
        , typename predicate<ParameterSpec>::type
        , typename has_default<ParameterSpec>::type
      > type;
  };

  template <class T>
  struct is_named_argument
    : mpl::or_<
          is_template_keyword<T>
        , is_tagged_argument<T>
      >
  {};
  
  // Returns mpl::true_ iff the given ParameterRequirements are
  // satisfied by ArgList.
  template <class ArgList, class ParameterRequirements>
  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<bound, void_>
        , 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_<satisfies::value> type;
#endif
  };

  // Returns mpl::true_ if the requirements of the given ParameterSpec
  // are satisfied by ArgList.
  template <class ArgList, class ParameterSpec>
  struct satisfies_requirements_of
    : satisfies<
          ArgList
        , typename as_parameter_requirements<ParameterSpec>::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 <class UsedArgs, class Spec, class Arg, class TagFn>
  struct tag_deduced
  {
      typedef mpl::pair<
          typename mpl::apply_wrap2<TagFn, typename tag_type<Spec>::type, Arg>::type
        , typename aux::insert_<UsedArgs, typename tag_type<Spec>::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_<mpl::and_<
              condition
            , aux::has_key_<UsedArgs, typename tag_type<spec>::type>
          > >
      ));

      typedef typename mpl::eval_if<
          condition
        , tag_deduced<UsedArgs, spec, Argument, TagFn>
        , deduce_tag<Argument, ArgumentPack, typename DeducedArgs::tail, UsedArgs, TagFn>
      >::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<DeducedArgs, void_>
        , mpl::pair<void_, UsedArgs>
        , deduce_tag0<Argument, ArgumentPack, DeducedArgs, UsedArgs, TagFn>
      >::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 <class UsedArgs, class Tagged>
  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<parameter_spec>::type tag_;

      typedef is_named_argument<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_deduced<parameter_spec>, 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<UsedArgs, argument>
        , mpl::identity<UsedArgs>
      >::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_<is_tagged, positional>
        , mpl::pair<void_, used_args>
        , deduce_tag<argument, ArgumentPack, DeducedArgs, used_args, TagFn>
      >::type deduced_data;

      // If this parameter is explicitly tagged..
      typedef typename mpl::eval_if<
          is_tagged
        , mpl::identity<argument>                        // .. just use it
        , mpl::eval_if<                                  // .. else, if positional matching is turned on..
                positional
              , mpl::apply_wrap2<TagFn, tag_, argument>  // .. tag it positionally
              , mpl::first<deduced_data>                 // .. 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<Error, void_>
            , is_same<tagged, void_>
          >
        , parameter_::unmatched_argument<argument>
        , void_
      >::type error;

      typedef typename mpl::if_<
          is_same<tagged, void_>
        , ArgumentPack
        , arg_list<tagged, ArgumentPack>
      >::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<List, void_>
        , mpl::identity<mpl::pair<ArgumentPack, Error> >
        , make_arg_list0<List, DeducedArgs, TagFn, Positional, DeducedSet, ArgumentPack, Error>
      >::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 <class Spec, class Arg, class Tail = void_>
  struct item
  {
      typedef Spec spec;

#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
      typedef is_const<Arg> is_arg_const;
#endif

      typedef Arg arg;
      typedef Tail tail;
  };

  template <class Spec, class Arg, class Tail>
  struct make_item
  {
      typedef item<Spec, Arg, typename Tail::type> type;
  };

  // Creates a item typelist.
  template <class Spec, class Arg, class Tail>
  struct make_items
  {
      typedef typename mpl::eval_if<
          is_same<Arg, void_>
        , mpl::identity<void_>
        , make_item<Spec, Arg, Tail>
      >::type type;
  };

  // A typelist that stored deduced parameter specs.
  template <class ParameterSpec, class Tail = void_>
  struct deduced_item
  {
      typedef ParameterSpec spec;
      typedef Tail tail;
  };

  // Evaluate Tail and construct deduced_item list.
  template <class Spec, class Tail>
  struct make_deduced_item
  {
      typedef deduced_item<Spec, typename Tail::type> type;
  };

  template <class Spec, class Tail>
  struct make_deduced_items
  {
      typedef typename mpl::eval_if<
          is_same<Spec, void_>
        , mpl::identity<void_>
        , mpl::eval_if<
              is_deduced<Spec>
            , make_deduced_item<Spec, Tail>
            , Tail
          >
      >::type type;
  };

  // Generates:
  //
  //   make<
  //       parameter_spec#0, argument_type#0
  //     , make<
  //           parameter_spec#1, argument_type#1
  //         , ... mpl::identity<aux::empty_arg_list>
  //    ...>
  //   >
#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<void_>                                                          \
  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<void_>                                                              \
  BOOST_PP_REPEAT(n, BOOST_PARAMETER_right_angle, _)

  struct tag_keyword_arg
  {
      template <class K, class T>
      struct apply
        : tag<K,T>
      {};
  };

  struct tag_template_keyword_arg
  {
      template <class K, class T>
      struct apply
      {
          typedef template_keyword<K,T> 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 <class ArgumentPackAndError>
    struct match_base
      : mpl::if_<
            // mpl::and_<
            //    aux::satisfies_requirements_of<NamedList,PS0>
            //  , mpl::and_<
            //       aux::satisfies_requirements_of<NamedList,PS1>...
            //           ..., mpl::true_
            // ...> >
            
# define BOOST_PARAMETER_satisfies(z, n, text)                                      \
            mpl::and_<                                                              \
                aux::satisfies_requirements_of<                                     \
                    typename mpl::first<ArgumentPackAndError>::type                 \
                  , BOOST_PP_CAT(PS, n)>                                            \
                  ,
            mpl::and_<
                is_same<typename mpl::second<ArgumentPackAndError>::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<parameters>
          , 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<result>::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<class A0>
    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<result>::type result_type;
        typedef typename mpl::second<result>::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<class A0, class A1>
    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<result>::type result_type;
        typedef typename mpl::second<result>::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,<boost/parameter/aux_/overloads.hpp> \
    ))
#include BOOST_PP_ITERATE()

};

} // namespace parameter

} // namespace boost

#endif // BOOST_PARAMETERS_031014_HPP

