source: NonGTP/Boost/boost/lambda/detail/return_type_traits.hpp @ 857

Revision 857, 9.6 KB checked in by igarcia, 18 years ago (diff)
Line 
1//  return_type_traits.hpp -- Boost Lambda Library ---------------------------
2
3// Copyright (C) 1999, 2000 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
4//
5// Distributed under the Boost Software License, Version 1.0. (See
6// accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8//
9// For more information, see www.boost.org
10
11
12#ifndef BOOST_LAMBDA_RETURN_TYPE_TRAITS_HPP
13#define BOOST_LAMBDA_RETURN_TYPE_TRAITS_HPP
14
15#include "boost/mpl/has_xxx.hpp"
16
17#include <cstddef> // needed for the ptrdiff_t
18
19namespace boost {
20namespace lambda {
21
22using ::boost::type_traits::ice_and;
23using ::boost::type_traits::ice_or;
24using ::boost::type_traits::ice_not;
25
26// Much of the type deduction code for standard arithmetic types
27// from Gary Powell
28
29  // different arities:
30template <class Act, class A1> struct return_type_1; // 1-ary actions
31template <class Act, class A1, class A2> struct return_type_2; // 2-ary
32template <class Act, class Args> struct return_type_N; // >3- ary
33
34template <class Act, class A1> struct return_type_1_prot;
35template <class Act, class A1, class A2> struct return_type_2_prot; // 2-ary
36template <class Act, class A1> struct return_type_N_prot; // >3-ary
37
38
39namespace detail {
40
41template<class> class return_type_deduction_failure {};
42
43  // In some cases return type deduction should fail (an invalid lambda
44  // expression). Sometimes the lambda expression can be ok, the return type
45  // just is not deducible (user defined operators). Then return type deduction
46  // should never be entered at all, and the use of ret<> does this.
47  // However, for nullary lambda functors, return type deduction is always
48  // entered, and there seems to be no way around this.
49
50  // (the return type is part of the prototype of the non-template
51  // operator()(). The prototype is instantiated, even though the body
52  // is not.)
53 
54  // So, in the case the return type deduction should fail, it should not
55  // fail directly, but rather result in a valid but wrong return type,
56  // causing a compile time error only if the function is really called.
57
58
59
60} // end detail
61
62
63
64// return_type_X_prot classes --------------------------------------------
65// These classes are the first layer that gets instantiated from the
66// lambda_functor_base sig templates. It will check whether
67// the action is protectable and one of arguments is "protected" or its
68// evaluation will otherwise result in another lambda functor.
69// If this is a case, the result type will be another lambda functor.
70
71// The arguments are always non-reference types, except for comma action
72// where the right argument can be a reference too. This is because it
73// matters (in the builtin case) whether the argument is an lvalue or
74// rvalue: int i; i, 1 -> rvalue; 1, i -> lvalue
75
76template <class Act, class A> struct return_type_1_prot {
77public:
78  typedef typename
79    detail::IF<
80  //      is_protectable<Act>::value && is_lambda_functor<A>::value,
81      ice_and<is_protectable<Act>::value, is_lambda_functor<A>::value>::value,
82      lambda_functor<
83        lambda_functor_base<
84          Act,
85          tuple<typename detail::remove_reference_and_cv<A>::type>
86        >
87      >,
88      typename return_type_1<Act, A>::type
89    >::RET type; 
90};
91
92  // take care of the unavoidable instantiation for nullary case
93template<class Act> struct return_type_1_prot<Act, null_type> {
94  typedef null_type type;
95};
96 
97// Unary actions (result from unary operators)
98// do not have a default return type.
99template<class Act, class A> struct return_type_1 {
100   typedef typename
101     detail::return_type_deduction_failure<return_type_1> type;
102};
103
104
105namespace detail {
106
107  template <class T>
108  class protect_conversion {
109      typedef typename boost::remove_reference<T>::type non_ref_T;
110    public:
111
112  // add const to rvalues, so that all rvalues are stored as const in
113  // the args tuple
114    typedef typename detail::IF_type<
115//      boost::is_reference<T>::value && !boost::is_const<non_ref_T>::value,
116      ice_and<boost::is_reference<T>::value,
117              ice_not<boost::is_const<non_ref_T>::value>::value>::value,
118      detail::identity_mapping<T>,
119      const_copy_argument<non_ref_T> // handles funtion and array
120    >::type type;                      // types correctly
121  };
122
123} // end detail
124
125template <class Act, class A, class B> struct return_type_2_prot {
126
127// experimental feature
128  // We may have a lambda functor as a result type of a subexpression
129  // (if protect) has  been used.
130  // Thus, if one of the parameter types is a lambda functor, the result
131  // is a lambda functor as well.
132  // We need to make a conservative choise here.
133  // The resulting lambda functor stores all const reference arguments as
134  // const copies. References to non-const are stored as such.
135  // So if the source of the argument is a const open argument, a bound
136  // argument stored as a const reference, or a function returning a
137  // const reference, that information is lost. There is no way of
138  // telling apart 'real const references' from just 'LL internal
139  // const references' (or it would be really hard)
140
141  // The return type is a subclass of lambda_functor, which has a converting
142  // copy constructor. It can copy any lambda functor, that has the same
143  // action type and code, and a copy compatible argument tuple.
144
145
146  typedef typename boost::remove_reference<A>::type non_ref_A;
147  typedef typename boost::remove_reference<B>::type non_ref_B;
148
149typedef typename
150  detail::IF<
151//    is_protectable<Act>::value &&
152//      (is_lambda_functor<A>::value || is_lambda_functor<B>::value),
153    ice_and<is_protectable<Act>::value,
154            ice_or<is_lambda_functor<A>::value,
155                   is_lambda_functor<B>::value>::value>::value,
156    lambda_functor<
157      lambda_functor_base<
158        Act,
159        tuple<typename detail::protect_conversion<A>::type,
160              typename detail::protect_conversion<B>::type>
161      >
162    >,
163    typename return_type_2<Act, non_ref_A, non_ref_B>::type
164  >::RET type;
165};
166
167  // take care of the unavoidable instantiation for nullary case
168template<class Act> struct return_type_2_prot<Act, null_type, null_type> {
169  typedef null_type type;
170};
171  // take care of the unavoidable instantiation for nullary case
172template<class Act, class Other> struct return_type_2_prot<Act, Other, null_type> {
173  typedef null_type type;
174};
175  // take care of the unavoidable instantiation for nullary case
176template<class Act, class Other> struct return_type_2_prot<Act, null_type, Other> {
177  typedef null_type type;
178};
179
180  // comma is a special case, as the user defined operator can return
181  // an lvalue (reference) too, hence it must be handled at this level.
182template<class A, class B>
183struct return_type_2_comma
184{
185  typedef typename boost::remove_reference<A>::type non_ref_A;
186  typedef typename boost::remove_reference<B>::type non_ref_B;
187
188typedef typename
189  detail::IF<
190//  is_protectable<other_action<comma_action> >::value && // it is protectable
191//  (is_lambda_functor<A>::value || is_lambda_functor<B>::value),
192    ice_and<is_protectable<other_action<comma_action> >::value, // it is protectable
193            ice_or<is_lambda_functor<A>::value,
194                   is_lambda_functor<B>::value>::value>::value,
195    lambda_functor<
196      lambda_functor_base<
197        other_action<comma_action>,
198        tuple<typename detail::protect_conversion<A>::type,
199              typename detail::protect_conversion<B>::type>
200      >
201    >,
202    typename
203      return_type_2<other_action<comma_action>, non_ref_A, non_ref_B>::type
204  >::RET type1;
205
206   // if no user defined return_type_2 (or plain_return_type_2) specialization
207  // matches, then return the righthand argument
208  typedef typename
209    detail::IF<
210      boost::is_same<type1, detail::unspecified>::value,
211      B,
212      type1
213    >::RET type;
214
215};
216
217
218  // currently there are no protectable actions with > 2 args
219  // Note, that if there will be, lambda_functor_base will have to be
220  // changed to not get rid of references in Args elements
221
222template<class Act, class Args> struct return_type_N_prot {
223  typedef typename return_type_N<Act, Args>::type type;
224};
225
226  // take care of the unavoidable instantiation for nullary case
227template<class Act> struct return_type_N_prot<Act, null_type> {
228  typedef null_type type;
229};
230
231// handle different kind of actions ------------------------
232
233  // use the return type given in the bind invocation as bind<Ret>(...)
234template<int I, class Args, class Ret>
235struct return_type_N<function_action<I, Ret>, Args> {
236  typedef Ret type;
237};
238
239// ::result_type support
240
241namespace detail
242{
243
244BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type)
245
246template<class F> struct get_result_type
247{
248  typedef typename F::result_type type;
249};
250
251template<class F, class A> struct get_sig
252{
253  typedef typename function_adaptor<F>::template sig<A>::type type;
254};
255
256} // namespace detail
257
258  // Ret is detail::unspecified, so try to deduce return type
259template<int I, class Args>
260struct return_type_N<function_action<I, detail::unspecified>, Args > {
261
262  // in the case of function action, the first element in Args is
263  // some type of function
264  typedef typename Args::head_type Func;
265  typedef typename detail::remove_reference_and_cv<Func>::type plain_Func;
266
267public:
268  // pass the function to function_adaptor, and get the return type from
269  // that
270  typedef typename detail::IF<
271    detail::has_result_type<plain_Func>::value,
272    detail::get_result_type<plain_Func>,
273    detail::get_sig<plain_Func, Args>
274  >::RET::type type;
275};
276
277
278} // namespace lambda
279} // namespace boost
280
281#endif
282
283
284
Note: See TracBrowser for help on using the repository browser.