1 // Boost result_of library
2 
3 //  Copyright Douglas Gregor 2003-2004. Use, modification and
4 //  distribution is subject to the Boost Software License, Version
5 //  1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 //  http://www.boost.org/LICENSE_1_0.txt)
7 
8 // Examples:
9 //   To run the default test:
10 //   $ cd libs/utility/test && bjam
11 //   To test decltype on g++ 2.7:
12 //   $ cd libs/utility/test && bjam cxxflags="-std=c++11 -D BOOST_RESULT_OF_USE_DECLTYPE"
13 
14 #include <boost/config.hpp>
15 
16 // For more information, see http://www.boost.org/libs/utility
17 #include <boost/utility/result_of.hpp>
18 #include <utility>
19 #include <boost/static_assert.hpp>
20 #include <boost/type_traits/is_same.hpp>
21 
22 struct int_result_type
23 {
24   typedef int result_type;
25   result_type operator()(float);
26 };
27 
28 struct int_result_of
29 {
30   template<typename F> struct result { typedef int type; };
31   result<int_result_of(double)>::type operator()(double);
32   result<const int_result_of(double)>::type operator()(double) const;
33   result<int_result_of()>::type operator()();
34   result<volatile int_result_of()>::type operator()() volatile;
35 };
36 
37 struct int_result_type_and_float_result_of_and_char_return
38 {
39   typedef int result_type;
40   template<typename F> struct result { typedef float type; };
41   char operator()(char);
42 };
43 
44 template<typename T>
45 struct int_result_type_template
46 {
47   typedef int result_type;
48   result_type operator()(float);
49 };
50 
51 template<typename T>
52 struct int_result_of_template
53 {
54   template<typename F> struct result;
55   template<typename This, typename That> struct result<This(That)> { typedef int type; };
56   typename result<int_result_of_template<T>(double)>::type operator()(double);
57   typename result<const int_result_of_template<T>(double)>::type operator()(double) const;
58   typename result<int_result_of_template<T>(double)>::type operator()();
59   typename result<volatile int_result_of_template<T>(double)>::type operator()() volatile;
60 };
61 
62 template<typename T>
63 struct int_result_type_and_float_result_of_and_char_return_template
64 {
65   typedef int result_type;
66   template<typename F> struct result;
67   template<typename This, typename That> struct result<This(That)> { typedef float type; };
68   char operator()(char);
69 };
70 
71 template<typename T>
72 struct cv_overload_check {};
73 
74 struct result_of_member_function_template
75 {
76   template<typename F> struct result;
77 
78   template<typename This, typename That> struct result<This(That)> { typedef That type; };
79   template<class T> typename result<result_of_member_function_template(T)>::type operator()(T);
80 
81   template<typename This, typename That> struct result<const This(That)> { typedef cv_overload_check<const That> type; };
82   template<class T> typename result<const result_of_member_function_template(T)>::type operator()(T) const;
83 
84   template<typename This, typename That> struct result<volatile This(That)> { typedef cv_overload_check<volatile That> type; };
85   template<class T> typename result<volatile result_of_member_function_template(T)>::type operator()(T) volatile;
86 
87   template<typename This, typename That> struct result<const volatile This(That)> { typedef cv_overload_check<const volatile That> type; };
88   template<class T> typename result<const volatile result_of_member_function_template(T)>::type operator()(T) const volatile;
89 
90   template<typename This, typename That> struct result<This(That &, That)> { typedef That & type; };
91   template<class T> typename result<result_of_member_function_template(T &, T)>::type operator()(T &, T);
92 
93   template<typename This, typename That> struct result<This(That const &, That)> { typedef That const & type; };
94   template<class T> typename result<result_of_member_function_template(T const &, T)>::type operator()(T const &, T);
95 
96   template<typename This, typename That> struct result<This(That volatile &, That)> { typedef That volatile & type; };
97   template<class T> typename result<result_of_member_function_template(T volatile &, T)>::type operator()(T volatile &, T);
98 
99   template<typename This, typename That> struct result<This(That const volatile &, That)> { typedef That const volatile & type; };
100   template<class T> typename result<result_of_member_function_template(T const volatile &, T)>::type operator()(T const volatile &, T);
101 };
102 
103 struct no_result_type_or_result
104 {
105   short operator()(double);
106   cv_overload_check<const short> operator()(double) const;
107   cv_overload_check<volatile short> operator()(double) volatile;
108   cv_overload_check<const volatile short> operator()(double) const volatile;
109   int operator()();
110   cv_overload_check<const int> operator()() const;
111   cv_overload_check<volatile int> operator()() volatile;
112   cv_overload_check<const volatile int> operator()() const volatile;
113 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
114   short operator()(int&&);
115   int operator()(int&);
116   long operator()(int const&);
117 #endif
118 };
119 
120 template<typename T>
121 struct no_result_type_or_result_template
122 {
123   short operator()(double);
124   cv_overload_check<const short> operator()(double) const;
125   cv_overload_check<volatile short> operator()(double) volatile;
126   cv_overload_check<const volatile short> operator()(double) const volatile;
127   int operator()();
128   cv_overload_check<const int> operator()() const;
129   cv_overload_check<volatile int> operator()() volatile;
130   cv_overload_check<const volatile int> operator()() const volatile;
131 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
132   short operator()(int&&);
133   int operator()(int&);
134   long operator()(int const&);
135 #endif
136 };
137 
138 // sfinae_tests are derived from example code from Joel de Guzman,
139 // which demonstrated the interaction between result_of and SFINAE.
140 template <typename F, typename Arg>
141 typename boost::result_of<F(Arg const&)>::type
sfinae_test(F f,Arg const & arg)142 sfinae_test(F f, Arg const& arg)
143 {
144     return f(arg);
145 }
146 
147 template <typename F, typename Arg>
148 typename boost::result_of<F(Arg&)>::type
sfinae_test(F f,Arg & arg)149 sfinae_test(F f, Arg& arg)
150 {
151     return f(arg);
152 }
153 
sfinae_test_f(int & i)154 int sfinae_test_f(int& i)
155 {
156     return i;
157 }
158 
159 struct X {};
160 
main()161 int main()
162 {
163   using namespace boost;
164 
165   typedef int (*func_ptr)(float, double);
166   typedef int (&func_ref)(float, double);
167   typedef int (*func_ptr_0)();
168   typedef int (&func_ref_0)();
169   typedef void (*func_ptr_void)(float, double);
170   typedef void (&func_ref_void)(float, double);
171   typedef void (*func_ptr_void_0)();
172   typedef void (&func_ref_void_0)();
173   typedef int (X::*mem_func_ptr)(float);
174   typedef int (X::*mem_func_ptr_c)(float) const;
175   typedef int (X::*mem_func_ptr_v)(float) volatile;
176   typedef int (X::*mem_func_ptr_cv)(float) const volatile;
177   typedef int (X::*mem_func_ptr_0)();
178 
179   BOOST_STATIC_ASSERT((is_same<result_of<int_result_type(float)>::type, int>::value));
180   BOOST_STATIC_ASSERT((is_same<result_of<int_result_of(double)>::type, int>::value));
181   BOOST_STATIC_ASSERT((is_same<result_of<const int_result_of(double)>::type, int>::value));
182   BOOST_STATIC_ASSERT((is_same<result_of<int_result_type_template<void>(float)>::type, int>::value));
183   BOOST_STATIC_ASSERT((is_same<result_of<int_result_of_template<void>(double)>::type, int>::value));
184   BOOST_STATIC_ASSERT((is_same<result_of<const int_result_of_template<void>(double)>::type, int>::value));
185 
186   BOOST_STATIC_ASSERT((is_same<tr1_result_of<int_result_type(float)>::type, int>::value));
187   BOOST_STATIC_ASSERT((is_same<tr1_result_of<int_result_of(double)>::type, int>::value));
188   BOOST_STATIC_ASSERT((is_same<tr1_result_of<const int_result_of(double)>::type, int>::value));
189   BOOST_STATIC_ASSERT((is_same<tr1_result_of<int_result_type_template<void>(float)>::type, int>::value));
190   BOOST_STATIC_ASSERT((is_same<tr1_result_of<int_result_of_template<void>(double)>::type, int>::value));
191   BOOST_STATIC_ASSERT((is_same<tr1_result_of<const int_result_of_template<void>(double)>::type, int>::value));
192 
193   BOOST_STATIC_ASSERT((is_same<tr1_result_of<int_result_of(void)>::type, void>::value));
194   BOOST_STATIC_ASSERT((is_same<tr1_result_of<volatile int_result_of(void)>::type, void>::value));
195   BOOST_STATIC_ASSERT((is_same<tr1_result_of<int_result_of_template<void>(void)>::type, void>::value));
196   BOOST_STATIC_ASSERT((is_same<tr1_result_of<volatile int_result_of_template<void>(void)>::type, void>::value));
197 
198   // Prior to decltype, result_of could not deduce the return type
199   // of nullary function objects unless they exposed a result_type.
200 #if defined(BOOST_RESULT_OF_USE_DECLTYPE)
201   BOOST_STATIC_ASSERT((is_same<result_of<int_result_of(void)>::type, int>::value));
202   BOOST_STATIC_ASSERT((is_same<result_of<volatile int_result_of(void)>::type, int>::value));
203   BOOST_STATIC_ASSERT((is_same<result_of<int_result_of_template<void>(void)>::type, int>::value));
204   BOOST_STATIC_ASSERT((is_same<result_of<volatile int_result_of_template<void>(void)>::type, int>::value));
205 #else
206   BOOST_STATIC_ASSERT((is_same<result_of<int_result_of(void)>::type, void>::value));
207   BOOST_STATIC_ASSERT((is_same<result_of<volatile int_result_of(void)>::type, void>::value));
208   BOOST_STATIC_ASSERT((is_same<result_of<int_result_of_template<void>(void)>::type, void>::value));
209   BOOST_STATIC_ASSERT((is_same<result_of<volatile int_result_of_template<void>(void)>::type, void>::value));
210 #endif
211 
212   // Prior to decltype, result_of ignored a nested result<> if
213   // result_type was defined. After decltype, result_of deduces the
214   // actual return type of the function object, ignoring both
215   // result<> and result_type.
216 #if defined(BOOST_RESULT_OF_USE_DECLTYPE)
217   BOOST_STATIC_ASSERT((is_same<result_of<int_result_type_and_float_result_of_and_char_return(char)>::type, char>::value));
218   BOOST_STATIC_ASSERT((is_same<result_of<int_result_type_and_float_result_of_and_char_return_template<void>(char)>::type, char>::value));
219 #else
220   BOOST_STATIC_ASSERT((is_same<result_of<int_result_type_and_float_result_of_and_char_return(char)>::type, int>::value));
221   BOOST_STATIC_ASSERT((is_same<result_of<int_result_type_and_float_result_of_and_char_return_template<void>(char)>::type, int>::value));
222 #endif
223 
224   BOOST_STATIC_ASSERT((is_same<tr1_result_of<int_result_type_and_float_result_of_and_char_return(char)>::type, int>::value));
225   BOOST_STATIC_ASSERT((is_same<tr1_result_of<int_result_type_and_float_result_of_and_char_return_template<void>(char)>::type, int>::value));
226 
227   BOOST_STATIC_ASSERT((is_same<result_of<func_ptr(char, float)>::type, int>::value));
228   BOOST_STATIC_ASSERT((is_same<result_of<func_ref(char, float)>::type, int>::value));
229   BOOST_STATIC_ASSERT((is_same<result_of<func_ptr_0()>::type, int>::value));
230   BOOST_STATIC_ASSERT((is_same<result_of<func_ref_0()>::type, int>::value));
231   BOOST_STATIC_ASSERT((is_same<result_of<func_ptr_void(char, float)>::type, void>::value));
232   BOOST_STATIC_ASSERT((is_same<result_of<func_ref_void(char, float)>::type, void>::value));
233   BOOST_STATIC_ASSERT((is_same<result_of<func_ptr_void_0()>::type, void>::value));
234   BOOST_STATIC_ASSERT((is_same<result_of<func_ref_void_0()>::type, void>::value));
235   BOOST_STATIC_ASSERT((is_same<result_of<mem_func_ptr(X,char)>::type, int>::value));
236   BOOST_STATIC_ASSERT((is_same<result_of<mem_func_ptr_c(X,char)>::type, int>::value));
237   BOOST_STATIC_ASSERT((is_same<result_of<mem_func_ptr_v(X,char)>::type, int>::value));
238   BOOST_STATIC_ASSERT((is_same<result_of<mem_func_ptr_cv(X,char)>::type, int>::value));
239   BOOST_STATIC_ASSERT((is_same<result_of<mem_func_ptr_0(X)>::type, int>::value));
240 
241   BOOST_STATIC_ASSERT((is_same<tr1_result_of<func_ptr(char, float)>::type, int>::value));
242   BOOST_STATIC_ASSERT((is_same<tr1_result_of<func_ref(char, float)>::type, int>::value));
243   BOOST_STATIC_ASSERT((is_same<tr1_result_of<func_ptr_0()>::type, int>::value));
244   BOOST_STATIC_ASSERT((is_same<tr1_result_of<func_ref_0()>::type, int>::value));
245   BOOST_STATIC_ASSERT((is_same<tr1_result_of<func_ptr_void(char, float)>::type, void>::value));
246   BOOST_STATIC_ASSERT((is_same<tr1_result_of<func_ref_void(char, float)>::type, void>::value));
247   BOOST_STATIC_ASSERT((is_same<tr1_result_of<func_ptr_void_0()>::type, void>::value));
248   BOOST_STATIC_ASSERT((is_same<tr1_result_of<func_ref_void_0()>::type, void>::value));
249   BOOST_STATIC_ASSERT((is_same<tr1_result_of<mem_func_ptr(X,char)>::type, int>::value));
250   BOOST_STATIC_ASSERT((is_same<tr1_result_of<mem_func_ptr_c(X,char)>::type, int>::value));
251   BOOST_STATIC_ASSERT((is_same<tr1_result_of<mem_func_ptr_v(X,char)>::type, int>::value));
252   BOOST_STATIC_ASSERT((is_same<tr1_result_of<mem_func_ptr_cv(X,char)>::type, int>::value));
253   BOOST_STATIC_ASSERT((is_same<tr1_result_of<mem_func_ptr_0(X)>::type, int>::value));
254   BOOST_STATIC_ASSERT((is_same<tr1_result_of<func_ptr(void)>::type, int>::value));
255   BOOST_STATIC_ASSERT((is_same<tr1_result_of<func_ref(void)>::type, int>::value));
256 
257   BOOST_STATIC_ASSERT((is_same<result_of<result_of_member_function_template(double)>::type, double>::value));
258   BOOST_STATIC_ASSERT((is_same<result_of<const result_of_member_function_template(double)>::type, cv_overload_check<const double> >::value));
259   BOOST_STATIC_ASSERT((is_same<result_of<volatile result_of_member_function_template(double)>::type, cv_overload_check<volatile double> >::value));
260   BOOST_STATIC_ASSERT((is_same<result_of<const volatile result_of_member_function_template(double)>::type, cv_overload_check<const volatile double> >::value));
261   BOOST_STATIC_ASSERT((is_same<result_of<result_of_member_function_template(int &, int)>::type, int &>::value));
262   BOOST_STATIC_ASSERT((is_same<result_of<result_of_member_function_template(int const &, int)>::type, int const &>::value));
263   BOOST_STATIC_ASSERT((is_same<result_of<result_of_member_function_template(int volatile &, int)>::type, int volatile &>::value));
264   BOOST_STATIC_ASSERT((is_same<result_of<result_of_member_function_template(int const volatile &, int)>::type, int const volatile &>::value));
265 
266   BOOST_STATIC_ASSERT((is_same<tr1_result_of<result_of_member_function_template(double)>::type, double>::value));
267   BOOST_STATIC_ASSERT((is_same<tr1_result_of<const result_of_member_function_template(double)>::type, cv_overload_check<const double> >::value));
268   BOOST_STATIC_ASSERT((is_same<tr1_result_of<volatile result_of_member_function_template(double)>::type, cv_overload_check<volatile double> >::value));
269   BOOST_STATIC_ASSERT((is_same<tr1_result_of<const volatile result_of_member_function_template(double)>::type, cv_overload_check<const volatile double> >::value));
270   BOOST_STATIC_ASSERT((is_same<tr1_result_of<result_of_member_function_template(int &, int)>::type, int &>::value));
271   BOOST_STATIC_ASSERT((is_same<tr1_result_of<result_of_member_function_template(int const &, int)>::type, int const &>::value));
272   BOOST_STATIC_ASSERT((is_same<tr1_result_of<result_of_member_function_template(int volatile &, int)>::type, int volatile &>::value));
273   BOOST_STATIC_ASSERT((is_same<tr1_result_of<result_of_member_function_template(int const volatile &, int)>::type, int const volatile &>::value));
274 
275   typedef int (*pf_t)(int);
276   BOOST_STATIC_ASSERT((is_same<result_of<pf_t(int)>::type, int>::value));
277   BOOST_STATIC_ASSERT((is_same<result_of<pf_t const(int)>::type,int>::value));
278 
279   BOOST_STATIC_ASSERT((is_same<tr1_result_of<pf_t(int)>::type, int>::value));
280   BOOST_STATIC_ASSERT((is_same<tr1_result_of<pf_t const(int)>::type,int>::value));
281 
282 #if defined(BOOST_RESULT_OF_USE_DECLTYPE) || defined(BOOST_RESULT_OF_USE_TR1_WITH_DECLTYPE_FALLBACK)
283   BOOST_STATIC_ASSERT((is_same<result_of<no_result_type_or_result(double)>::type, short>::value));
284   BOOST_STATIC_ASSERT((is_same<result_of<const no_result_type_or_result(double)>::type, cv_overload_check<const short> >::value));
285   BOOST_STATIC_ASSERT((is_same<result_of<volatile no_result_type_or_result(double)>::type, cv_overload_check<volatile short> >::value));
286   BOOST_STATIC_ASSERT((is_same<result_of<const volatile no_result_type_or_result(double)>::type, cv_overload_check<const volatile short> >::value));
287   BOOST_STATIC_ASSERT((is_same<result_of<no_result_type_or_result(void)>::type, int>::value));
288   BOOST_STATIC_ASSERT((is_same<result_of<const no_result_type_or_result(void)>::type, cv_overload_check<const int> >::value));
289   BOOST_STATIC_ASSERT((is_same<result_of<volatile no_result_type_or_result(void)>::type, cv_overload_check<volatile int> >::value));
290   BOOST_STATIC_ASSERT((is_same<result_of<const volatile no_result_type_or_result(void)>::type, cv_overload_check<const volatile int> >::value));
291 
292   BOOST_STATIC_ASSERT((is_same<result_of<no_result_type_or_result_template<void>(double)>::type, short>::value));
293   BOOST_STATIC_ASSERT((is_same<result_of<const no_result_type_or_result_template<void>(double)>::type, cv_overload_check<const short> >::value));
294   BOOST_STATIC_ASSERT((is_same<result_of<volatile no_result_type_or_result_template<void>(double)>::type, cv_overload_check<volatile short> >::value));
295   BOOST_STATIC_ASSERT((is_same<result_of<const volatile no_result_type_or_result_template<void>(double)>::type, cv_overload_check<const volatile short> >::value));
296   BOOST_STATIC_ASSERT((is_same<result_of<no_result_type_or_result_template<void>(void)>::type, int>::value));
297   BOOST_STATIC_ASSERT((is_same<result_of<const no_result_type_or_result_template<void>(void)>::type, cv_overload_check<const int> >::value));
298   BOOST_STATIC_ASSERT((is_same<result_of<volatile no_result_type_or_result_template<void>(void)>::type, cv_overload_check<volatile int> >::value));
299   BOOST_STATIC_ASSERT((is_same<result_of<const volatile no_result_type_or_result_template<void>(void)>::type, cv_overload_check<const volatile int> >::value));
300 
301   BOOST_STATIC_ASSERT((is_same<result_of<func_ptr&(char, float)>::type, int>::value));
302   BOOST_STATIC_ASSERT((is_same<result_of<func_ptr const&(char, float)>::type, int>::value));
303   BOOST_STATIC_ASSERT((is_same<result_of<int_result_of&(double)>::type, int>::value));
304   BOOST_STATIC_ASSERT((is_same<result_of<int_result_of const&(double)>::type, int>::value));
305 
306 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
307   BOOST_STATIC_ASSERT((is_same<result_of<no_result_type_or_result(int&&)>::type, short>::value));
308   BOOST_STATIC_ASSERT((is_same<result_of<no_result_type_or_result(int&)>::type, int>::value));
309   BOOST_STATIC_ASSERT((is_same<result_of<no_result_type_or_result(int const&)>::type, long>::value));
310   BOOST_STATIC_ASSERT((is_same<result_of<no_result_type_or_result_template<void>(int&&)>::type, short>::value));
311   BOOST_STATIC_ASSERT((is_same<result_of<no_result_type_or_result_template<void>(int&)>::type, int>::value));
312   BOOST_STATIC_ASSERT((is_same<result_of<no_result_type_or_result_template<void>(int const&)>::type, long>::value));
313 #endif
314 #endif
315 
316 #if defined(BOOST_RESULT_OF_USE_DECLTYPE) || defined(BOOST_RESULT_OF_USE_TR1_WITH_DECLTYPE_FALLBACK)
317   int i = 123;
318   sfinae_test(sfinae_test_f, i);
319 #endif // defined(BOOST_RESULT_OF_USE_DECLTYPE) || defined(BOOST_RESULT_OF_USE_TR1_WITH_DECLTYPE_FALLBACK)
320 
321   return 0;
322 }
323