1 ///////////////////////////////////////////////////////////////////////////////
2 /// \file poly_function.hpp
3 /// A wrapper that makes a tr1-style function object that handles const
4 /// and non-const refs and reference_wrapper arguments, too, and forwards
5 /// the arguments on to the specified implementation.
6 //
7 //  Copyright 2008 Eric Niebler. Distributed under the Boost
8 //  Software License, Version 1.0. (See accompanying file
9 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10 
11 #ifndef BOOST_PROTO_DETAIL_POLY_FUNCTION_EAN_2008_05_02
12 #define BOOST_PROTO_DETAIL_POLY_FUNCTION_EAN_2008_05_02
13 
14 #include <boost/ref.hpp>
15 #include <boost/mpl/bool.hpp>
16 #include <boost/mpl/void.hpp>
17 #include <boost/mpl/size_t.hpp>
18 #include <boost/mpl/eval_if.hpp>
19 #include <boost/preprocessor/cat.hpp>
20 #include <boost/preprocessor/facilities/intercept.hpp>
21 #include <boost/preprocessor/iteration/iterate.hpp>
22 #include <boost/preprocessor/repetition/enum.hpp>
23 #include <boost/preprocessor/repetition/enum_params.hpp>
24 #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
25 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
26 #include <boost/proto/proto_fwd.hpp>
27 #include <boost/proto/detail/is_noncopyable.hpp>
28 
29 #ifdef _MSC_VER
30 # pragma warning(push)
31 # pragma warning(disable: 4181) // const applied to reference type
32 #endif
33 
34 namespace boost { namespace proto { namespace detail
35 {
36 
37     ////////////////////////////////////////////////////////////////////////////////////////////////
38     template<typename T>
39     struct normalize_arg
40     {
41         typedef typename mpl::if_c<is_noncopyable<T>::value, T &, T>::type type;
42         typedef T &reference;
43     };
44 
45     template<typename T>
46     struct normalize_arg<T const>
47     {
48         typedef typename mpl::if_c<is_noncopyable<T>::value, T const &, T>::type type;
49         typedef T const &reference;
50     };
51 
52     template<typename T>
53     struct normalize_arg<T &>
54     {
55         typedef typename mpl::if_c<is_noncopyable<T>::value, T &, T>::type type;
56         typedef T &reference;
57     };
58 
59     template<typename T>
60     struct normalize_arg<T const &>
61     {
62         typedef typename mpl::if_c<is_noncopyable<T>::value, T const &, T>::type type;
63         typedef T const &reference;
64     };
65 
66     template<typename T>
67     struct normalize_arg<boost::reference_wrapper<T> >
68     {
69         typedef T &type;
70         typedef T &reference;
71     };
72 
73     template<typename T>
74     struct normalize_arg<boost::reference_wrapper<T> const>
75     {
76         typedef T &type;
77         typedef T &reference;
78     };
79 
80     template<typename T>
81     struct normalize_arg<boost::reference_wrapper<T> &>
82     {
83         typedef T &type;
84         typedef T &reference;
85     };
86 
87     template<typename T>
88     struct normalize_arg<boost::reference_wrapper<T> const &>
89     {
90         typedef T &type;
91         typedef T &reference;
92     };
93 
94     ////////////////////////////////////////////////////////////////////////////////////////////////
95     template<typename T>
96     struct arg
97     {
98         typedef T const &type;
99 
argboost::proto::detail::arg100         arg(type t)
101           : value(t)
102         {}
103 
operator typeboost::proto::detail::arg104         operator type() const
105         {
106             return this->value;
107         }
108 
operator ()boost::proto::detail::arg109         type operator()() const
110         {
111             return this->value;
112         }
113 
114     private:
115         arg &operator =(arg const &);
116         type value;
117     };
118 
119     template<typename T>
120     struct arg<T &>
121     {
122         typedef T &type;
123 
argboost::proto::detail::arg124         arg(type t)
125           : value(t)
126         {}
127 
operator typeboost::proto::detail::arg128         operator type() const
129         {
130             return this->value;
131         }
132 
operator ()boost::proto::detail::arg133         type operator()() const
134         {
135             return this->value;
136         }
137 
138     private:
139         arg &operator =(arg const &);
140         type value;
141     };
142 
143     ////////////////////////////////////////////////////////////////////////////////////////////////
144     template<typename T, typename Void = void>
145     struct is_poly_function
146       : mpl::false_
147     {};
148 
149     template<typename T>
150     struct is_poly_function<T, typename T::is_poly_function_base_>
151       : mpl::true_
152     {};
153 
154     ////////////////////////////////////////////////////////////////////////////////////////////////
155     #define BOOST_PROTO_POLY_FUNCTION()                                                             \
156         typedef void is_poly_function_base_;                                                        \
157         /**/
158 
159     ////////////////////////////////////////////////////////////////////////////////////////////////
160     struct poly_function_base
161     {
162         /// INTERNAL ONLY
163         BOOST_PROTO_POLY_FUNCTION()
164     };
165 
166     ////////////////////////////////////////////////////////////////////////////////////////////////
167     template<typename Derived, typename NullaryResult = void>
168     struct poly_function
169       : poly_function_base
170     {
171         template<typename Sig>
172         struct result;
173 
174         template<typename This>
175         struct result<This()>
176           : Derived::template impl<>
177         {
178             typedef typename result::result_type type;
179         };
180 
operator ()boost::proto::detail::poly_function181         NullaryResult operator()() const
182         {
183             result<Derived const()> impl;
184             return impl();
185         }
186 
187         #include <boost/proto/detail/poly_function_funop.hpp>
188     };
189 
190     template<typename T>
191     struct wrap_t;
192 
193     typedef char poly_function_t;
194     typedef char (&mono_function_t)[2];
195     typedef char (&unknown_function_t)[3];
196 
197     template<typename T> poly_function_t test_poly_function(T *, wrap_t<typename T::is_poly_function_base_> * = 0);
198     template<typename T> mono_function_t test_poly_function(T *, wrap_t<typename T::result_type> * = 0);
199     template<typename T> unknown_function_t test_poly_function(T *, ...);
200 
201     ////////////////////////////////////////////////////////////////////////////////////////////////
202     template<typename Fun, typename Sig, typename Switch = mpl::size_t<sizeof(test_poly_function<Fun>(0,0))> >
203     struct poly_function_traits
204     {
205         typedef typename Fun::template result<Sig>::type result_type;
206         typedef Fun function_type;
207     };
208 
209     ////////////////////////////////////////////////////////////////////////////////////////////////
210     template<typename Fun, typename Sig>
211     struct poly_function_traits<Fun, Sig, mpl::size_t<sizeof(mono_function_t)> >
212     {
213         typedef typename Fun::result_type result_type;
214         typedef Fun function_type;
215     };
216 
217     ////////////////////////////////////////////////////////////////////////////////////////////////
218     template<typename PolyFunSig, bool IsPolyFunction>
219     struct as_mono_function_impl;
220 
221     ////////////////////////////////////////////////////////////////////////////////////////////////
222     template<typename PolyFunSig>
223     struct as_mono_function;
224 
225     #include <boost/proto/detail/poly_function_traits.hpp>
226 
227 }}} // namespace boost::proto::detail
228 
229 #ifdef _MSC_VER
230 # pragma warning(pop)
231 #endif
232 
233 #endif
234 
235