Add SCons configure checks
[senf.git] / boost_ext / boost / parameter / parameters.hpp
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
46 namespace boost {
47
48 template<class T> class reference_wrapper;
49
50 namespace parameter {
51
52 namespace 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 //
69 template <class Tag, class Predicate = aux::use_default>
70 struct required
71 {
72     typedef Tag key_type;
73     typedef Predicate predicate;
74 };
75
76 template <class Tag, class Predicate = aux::use_default>
77 struct optional
78 {
79     typedef Tag key_type;
80     typedef Predicate predicate;
81 };
82
83 template <class Tag>
84 struct unnamed
85 {
86     typedef Tag key_type;
87 };
88
89 namespace 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
303 template<
304      class PS0
305    , BOOST_PP_ENUM_SHIFTED(BOOST_PARAMETER_MAX_ARITY, BOOST_PARAMETER_TEMPLATE_ARGS, _)
306 >
307 struct 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