source: NonGTP/Boost/boost/parameter/parameters.hpp @ 857

Revision 857, 13.6 KB checked in by igarcia, 19 years ago (diff)
RevLine 
[857]1// Copyright David Abrahams, Daniel Wallin 2003. Use, modification and
2// distribution is subject to the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at
4// http://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef BOOST_PARAMETERS_031014_HPP
7#define BOOST_PARAMETERS_031014_HPP
8
9#include <boost/detail/is_xxx.hpp>
10
11#include <boost/mpl/lambda.hpp>
12#include <boost/mpl/apply.hpp>
13#include <boost/mpl/always.hpp>
14#include <boost/mpl/and.hpp>
15#include <boost/mpl/or.hpp>
16#include <boost/mpl/if.hpp>
17#include <boost/mpl/identity.hpp>
18#include <boost/mpl/not.hpp>
19#include <boost/mpl/eval_if.hpp>
20
21#include <boost/type_traits/is_same.hpp>
22#include <boost/type_traits/remove_reference.hpp>
23
24#include <boost/preprocessor/repetition/enum.hpp>
25#include <boost/preprocessor/repetition/enum_params.hpp>
26#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
27#include <boost/preprocessor/arithmetic/sub.hpp>
28#include <boost/preprocessor/repetition/enum_shifted.hpp>
29#include <boost/preprocessor/repetition/enum_binary_params.hpp>
30#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
31#include <boost/preprocessor/seq/elem.hpp>
32#include <boost/preprocessor/iteration/iterate.hpp>
33#include <boost/preprocessor/facilities/intercept.hpp>
34#include <boost/preprocessor/cat.hpp>
35
36#include <boost/parameter/aux_/arg_list.hpp>
37#include <boost/parameter/aux_/yesno.hpp>
38#include <boost/parameter/aux_/void.hpp>
39#include <boost/parameter/aux_/default.hpp>
40#include <boost/parameter/aux_/unwrap_cv_reference.hpp>
41#include <boost/parameter/aux_/tagged_argument.hpp>
42#include <boost/parameter/aux_/tag.hpp>
43#include <boost/parameter/config.hpp>
44
45
46namespace boost {
47
48template<class T> class reference_wrapper;
49
50namespace parameter {
51
52namespace aux { struct use_default {}; }
53
54// These templates can be used to describe the treatment of particular
55// named parameters for the purposes of overload elimination with
56// SFINAE, by placing specializations in the parameters<...> list.  In
57// order for a treated function to participate in overload resolution:
58//
59//   - all keyword tags wrapped in required<...> must have a matching
60//     actual argument
61//
62//   - The actual argument type matched by every keyword tag
63//     associated with a predicate must satisfy that predicate
64//
65// If a keyword k is specified without an optional<...> or
66// required<...>, wrapper, it is treated as though optional<k> were
67// specified.
68//
69template <class Tag, class Predicate = aux::use_default>
70struct required
71{
72    typedef Tag key_type;
73    typedef Predicate predicate;
74};
75
76template <class Tag, class Predicate = aux::use_default>
77struct optional
78{
79    typedef Tag key_type;
80    typedef Predicate predicate;
81};
82
83template <class Tag>
84struct unnamed
85{
86    typedef Tag key_type;
87};
88
89namespace aux
90{
91  // Defines metafunctions, is_required and is_optional, that
92  // identify required<...> and optional<...> specializations.
93  BOOST_DETAIL_IS_XXX_DEF(required, required, 2)
94  BOOST_DETAIL_IS_XXX_DEF(optional, optional, 2)
95
96  //
97  // key_type, has_default, and predicate --
98  //
99  // These metafunctions accept a ParameterSpec and extract the
100  // keyword tag, whether or not a default is supplied for the
101  // parameter, and the predicate that the corresponding actual
102  // argument type is required match.
103  //
104  // a ParameterSpec is a specialization of either keyword<...>,
105  // required<...> or optional<...>.
106  //
107 
108  // helper for key_type<...>, below.
109  template <class T>
110  struct get_key_type
111  { typedef typename T::key_type type; };
112
113  template <class T>
114  struct key_type
115    : mpl::eval_if<
116          mpl::or_<
117              is_optional<T>
118            , is_required<T>
119          >
120        , get_key_type<T>
121        , mpl::identity<T>
122      >
123  {
124  };
125
126  template <class T>
127  struct has_default
128    : mpl::not_<typename is_required<T>::type>
129  {
130  };
131
132  // helper for get_predicate<...>, below
133  template <class T>
134  struct get_predicate_or_default
135  {
136      typedef T type;
137  };
138
139  template <>
140  struct get_predicate_or_default<use_default>
141  {
142      typedef mpl::always<mpl::true_> type;
143  };
144
145  // helper for predicate<...>, below
146  template <class T>
147  struct get_predicate
148  {
149      typedef typename
150          get_predicate_or_default<typename T::predicate>::type
151      type;
152  };
153
154  template <class T>
155  struct predicate
156    : mpl::eval_if<
157         mpl::or_<
158              is_optional<T>
159            , is_required<T>
160          >
161        , get_predicate<T>
162        , mpl::identity<mpl::always<mpl::true_> >
163      >
164  {
165  };
166
167
168  // Converts a ParameterSpec into a specialization of
169  // parameter_requirements.  We need to do this in order to get the
170  // key_type into the type in a way that can be conveniently matched
171  // by a satisfies(...) member function in arg_list.
172  template <class ParameterSpec>
173  struct as_parameter_requirements
174  {
175      typedef parameter_requirements<
176          typename key_type<ParameterSpec>::type
177        , typename predicate<ParameterSpec>::type
178        , typename has_default<ParameterSpec>::type
179      > type;
180  };
181
182  // Labels Arg with default keyword tag DefaultTag if it is not
183  // already a tagged_argument
184  template <class DefaultTag, class Arg>
185  struct as_tagged_argument
186    : mpl::eval_if<
187          is_tagged_argument<Arg>
188        , mpl::identity<Arg>
189        , tag<typename key_type<DefaultTag>::type, Arg const>
190      >
191  {};
192 
193#if BOOST_WORKAROUND(BOOST_MSVC, == 1200)  // ETI workaround
194  template <>
195  struct as_tagged_argument<int,int>
196  {
197      typedef int type;
198  };
199#endif
200
201  // Returns mpl::true_ iff the given ParameterRequirements are
202  // satisfied by ArgList.
203  template <class ArgList, class ParameterRequirements>
204  struct satisfies
205  {
206#if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
207      // VC7.1 can't handle the sizeof() implementation below,
208      // so we use this instead.
209      typedef typename mpl::apply_wrap2<
210          typename ArgList::binding
211        , typename ParameterRequirements::keyword
212        , void_
213      >::type bound;
214
215      typedef typename mpl::eval_if<
216          is_same<bound, void_>
217        , typename ParameterRequirements::has_default
218        , mpl::apply1<
219              typename ParameterRequirements::predicate
220            , typename remove_reference<bound>::type
221          >
222      >::type type;
223#else
224      BOOST_STATIC_CONSTANT(
225          bool, value = (
226              sizeof(
227                  aux::to_yesno(
228                      ArgList::satisfies((ParameterRequirements*)0)
229                  )
230              ) == sizeof(yes_tag)
231          )
232      );
233
234      typedef mpl::bool_<satisfies::value> type;
235#endif
236  };
237
238  // Returns mpl::true_ if the requirements of the given ParameterSpec
239  // are satisfied by ArgList.
240  template <class ArgList, class ParameterSpec>
241  struct satisfies_requirements_of
242    : satisfies<
243          ArgList
244        , typename as_parameter_requirements<ParameterSpec>::type
245      >
246  {};
247
248  // Helper for make_partial_arg_list, below.  Produce an arg_list
249  // node for the given ParameterSpec and ArgumentType, whose tail is
250  // determined by invoking the nullary metafunction TailFn.
251  template <class ParameterSpec, class ArgumentType, class TailFn>
252  struct make_arg_list
253  {
254      typedef arg_list<
255          typename as_tagged_argument<ParameterSpec,ArgumentType>::type
256        , typename TailFn::type
257      > type;
258  };
259
260  // Just like make_arg_list, except if ArgumentType is void_, the
261  // result is empty_arg_list.  Used to build arg_lists whose length
262  // depends on the number of non-default (void_) arguments passed to
263  // a class template.
264  template <
265      class ParameterSpec
266    , class ArgumentType
267    , class TailFn
268  >
269  struct make_partial_arg_list
270    : mpl::eval_if<
271          is_same<ArgumentType,void_>
272        , mpl::identity<empty_arg_list>
273        , make_arg_list<ParameterSpec, ArgumentType, TailFn>
274      >
275  {};
276
277  // Generates:
278  //
279  //   make<
280  //       parameter_spec#0, argument_type#0
281  //     , make<
282  //           parameter_spec#1, argument_type#1
283  //         , ... mpl::identity<aux::empty_arg_list>
284  //    ...>
285  //   >
286#define BOOST_PARAMETER_make_arg_list(z, n, names)      \
287      BOOST_PP_SEQ_ELEM(0,names)<                       \
288          BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(1,names), n),  \
289          BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(2,names), n),
290
291#define BOOST_PARAMETER_right_angle(z, n, text)    >
292   
293#define BOOST_PARAMETER_build_arg_list(n, make, parameter_spec, argument_type)      \
294  BOOST_PP_REPEAT(                                                                  \
295      n, BOOST_PARAMETER_make_arg_list, (make)(parameter_spec)(argument_type))      \
296  mpl::identity<aux::empty_arg_list>                                                \
297  BOOST_PP_REPEAT(n, BOOST_PARAMETER_right_angle, _)
298
299} // namespace aux
300
301#define BOOST_PARAMETER_TEMPLATE_ARGS(z, n, text) class BOOST_PP_CAT(PS, n) = aux::void_
302
303template<
304     class PS0
305   , BOOST_PP_ENUM_SHIFTED(BOOST_PARAMETER_MAX_ARITY, BOOST_PARAMETER_TEMPLATE_ARGS, _)
306>
307struct parameters
308{
309#undef BOOST_PARAMETER_TEMPLATE_ARGS
310
311    // if the elements of NamedList match the criteria of overload
312    // resolution, returns a type which can be constructed from
313    // parameters.  Otherwise, this is not a valid metafunction (no nested
314    // ::type).
315
316
317#ifndef BOOST_NO_SFINAE
318    // If NamedList satisfies the PS0, PS1, ..., this is a
319    // metafunction returning parameters.  Otherwise it
320    // has no nested ::type.
321    template <class NamedList>
322    struct match_base
323      : mpl::if_<
324            // mpl::and_<
325            //    aux::satisfies_requirements_of<NamedList,PS0>
326            //  , mpl::and_<
327            //       aux::satisfies_requirements_of<NamedList,PS1>...
328            //           ..., mpl::true_
329            // ...> >
330           
331# define BOOST_PARAMETER_satisfies(z, n, text)                                   \
332            mpl::and_<                                                              \
333                aux::satisfies_requirements_of<NamedList, BOOST_PP_CAT(PS, n)> ,
334     
335            BOOST_PP_REPEAT(BOOST_PARAMETER_MAX_ARITY, BOOST_PARAMETER_satisfies, _)
336            mpl::true_
337            BOOST_PP_REPEAT(BOOST_PARAMETER_MAX_ARITY, BOOST_PARAMETER_right_angle, _)
338
339# undef BOOST_PARAMETER_satisfies
340
341          , mpl::identity<parameters>
342          , aux::void_
343        >
344    {};
345#endif
346   
347    // Specializations are to be used as an optional argument to
348    // eliminate overloads via SFINAE
349    template<
350#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
351        // Borland simply can't handle default arguments in member
352        // class templates.  People wishing to write portable code can
353        // explicitly specify BOOST_PARAMETER_MAX_ARITY arguments
354        BOOST_PP_ENUM_PARAMS(BOOST_PARAMETER_MAX_ARITY, class A)
355#else
356        BOOST_PP_ENUM_BINARY_PARAMS(
357            BOOST_PARAMETER_MAX_ARITY, class A, = aux::void_ BOOST_PP_INTERCEPT
358        )
359#endif           
360    >
361    struct match
362# ifndef BOOST_NO_SFINAE
363      : match_base<
364            typename BOOST_PARAMETER_build_arg_list(
365                BOOST_PARAMETER_MAX_ARITY, aux::make_partial_arg_list, PS, A
366            )::type
367        >::type
368    {};
369# else
370    {
371        typedef parameters<
372            BOOST_PP_ENUM_PARAMS(BOOST_PARAMETER_MAX_ARITY, PS)
373        > type;
374    };
375# endif
376
377    //
378    // The function call operator is used to build an arg_list that
379    // labels the positional parameters and maintains whatever other
380    // tags may have been specified by the caller.
381    //
382    aux::empty_arg_list operator()() const
383    {
384       return aux::empty_arg_list();
385    }
386
387    template<class A0>
388    typename
389      aux::make_arg_list<PS0,A0, mpl::identity<aux::empty_arg_list> >
390    ::type
391    operator()( A0 const& a0) const
392    {
393        typedef typename
394          aux::make_arg_list<PS0, A0, mpl::identity<aux::empty_arg_list> >
395        ::type result_type;
396
397        return result_type(
398            a0
399            // , void_(), void_(), void_() ...
400            BOOST_PP_ENUM_TRAILING_PARAMS(
401                BOOST_PP_SUB(BOOST_PARAMETER_MAX_ARITY, 1)
402              , aux::void_() BOOST_PP_INTERCEPT)
403        );
404    }
405
406    template<class A0, class A1>
407    typename
408      aux::make_arg_list<
409          PS0,A0
410        , aux::make_arg_list<
411              PS1,A1
412            , mpl::identity<aux::empty_arg_list>
413          >
414      >
415    ::type
416    operator()(A0 const& a0, A1 const& a1) const
417    {
418        typedef typename
419          aux::make_arg_list<
420              PS0,A0
421            , aux::make_arg_list<
422                  PS1,A1
423                , mpl::identity<aux::empty_arg_list>
424              >
425          >
426        ::type result_type;
427
428
429        return result_type(
430            a0, a1
431            // , void_(), void_() ...
432            BOOST_PP_ENUM_TRAILING_PARAMS(
433                BOOST_PP_SUB(BOOST_PARAMETER_MAX_ARITY, 2)
434              , aux::void_() BOOST_PP_INTERCEPT)
435        );
436    }
437
438    // Higher arities are handled by the preprocessor
439#define BOOST_PP_ITERATION_PARAMS_1 (3,( \
440        3,BOOST_PARAMETER_MAX_ARITY,<boost/parameter/aux_/overloads.hpp> \
441    ))
442#include BOOST_PP_ITERATE()
443   
444#undef BOOST_PARAMETER_build_arg_list
445#undef BOOST_PARAMETER_make_arg_list
446#undef BOOST_PARAMETER_right_angle
447
448};
449
450} // namespace parameter
451
452} // namespace boost
453
454#endif // BOOST_PARAMETERS_031014_HPP
455
Note: See TracBrowser for help on using the repository browser.