1 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
2 // https://github.com/Dobiasd/FunctionalPlus
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 //  http://www.boost.org/LICENSE_1_0.txt)
6 
7 #include <doctest/doctest.h>
8 #include <functional>
9 #include <fplus/internal/invoke.hpp>
10 
11 #include <initializer_list>
12 #include <stdexcept>
13 #include <string>
14 #include <tuple>
15 
16 using namespace fplus;
17 
18 #if defined(_MSC_VER) && (_MSC_VER < 1910)
19 // only one test fails to compile with MSVC 2015, all tests pass with MSVC 2017
20 #define FPLUS_MSVC2015_BYPASS_FAILING_TESTS
21 #endif
22 
23 namespace
24 {
25 template <typename T>
26 struct identity
27 {
28   using type = T;
29 };
30 
31 template <typename Ret, typename Class, typename... Args>
cv_qualifiers(identity<Ret (Class::*)(Args...)>)32 auto cv_qualifiers(identity<Ret (Class::*)(Args...)>) {
33   return std::tuple<identity<Ret (Class::*)(Args...)>,
34                     identity<Ret (Class::*)(Args...) const>,
35                     identity<Ret (Class::*)(Args...) volatile>,
36                     identity<Ret (Class::*)(Args...) const volatile>>{};
37 }
38 
39 template <typename Ret, typename Class, typename... Args>
ref_qualifiers(identity<Ret (Class::*)(Args...)>)40 auto ref_qualifiers(identity<Ret (Class::*)(Args...)>)
41 {
42   return std::tuple<identity<Ret (Class::*)(Args...)&>,
43                     identity<Ret (Class::*)(Args...) &&>>{};
44 }
45 
46 template <typename Ret, typename Class, typename... Args>
ref_qualifiers(identity<Ret (Class::*)(Args...)const>)47 auto ref_qualifiers(identity<Ret (Class::*)(Args...) const>)
48 {
49   return std::tuple<identity<Ret (Class::*)(Args...) const&>,
50                     identity<Ret (Class::*)(Args...) const &&>>{};
51 }
52 
53 template <typename Ret, typename Class, typename... Args>
ref_qualifiers(identity<Ret (Class::*)(Args...)volatile>)54 auto ref_qualifiers(identity<Ret (Class::*)(Args...) volatile>)
55 {
56   return std::tuple<identity<Ret (Class::*)(Args...) volatile&>,
57                     identity<Ret (Class::*)(Args...) volatile &&>>{};
58 }
59 
60 template <typename Ret, typename Class, typename... Args>
ref_qualifiers(identity<Ret (Class::*)(Args...)const volatile>)61 auto ref_qualifiers(identity<Ret (Class::*)(Args...) const volatile>)
62 {
63   return std::tuple<identity<Ret (Class::*)(Args...) const volatile&>,
64                     identity<Ret (Class::*)(Args...) const volatile&&>>{};
65 }
66 
67 template <typename T>
ref_qualifiers(identity<T>)68 auto ref_qualifiers(identity<T>)
69 {
70   return std::tuple<identity<T&>, identity<T&&>>{};
71 }
72 
73 template <typename T>
all_qualifiers(identity<T> f)74 auto all_qualifiers(identity<T> f)
75 {
76   auto a = cv_qualifiers(f);
77   // make_index_sequence would work, but no need
78   auto b = ref_qualifiers(std::get<0>(a));
79   auto c = ref_qualifiers(std::get<1>(a));
80   auto d = ref_qualifiers(std::get<2>(a));
81   auto e = ref_qualifiers(std::get<3>(a));
82 
83   return std::make_tuple(std::get<0>(b),
84                          std::get<1>(b),
85                          std::get<0>(c),
86                          std::get<1>(c),
87                          std::get<0>(d),
88                          std::get<1>(d),
89                          std::get<0>(e),
90                          std::get<1>(e));
91 }
92 
93 template <typename... Args>
94 struct all_invocable;
95 
96 template <typename... TupleArgs, typename Class, typename... FuncArgs>
97 struct all_invocable<std::tuple<TupleArgs...>, Class, FuncArgs...>
98 {
99   using Tuple = std::tuple<TupleArgs...>;
100 
101   // two ::type, becaus of identity wrapper
102   template <std::size_t N, typename T>
103   using Elem = typename std::tuple_element<N, T>::type::type;
104 
105   static_assert(sizeof...(TupleArgs) == 8,
106                 "all_invocable applies to each cv-ref qualified overloads");
107 
108   // Class& because `&` functions can only be invokej on lvalue references
109   static constexpr bool value = internal::conjunction<
110       internal::is_invocable<Elem<0, Tuple>, Class&, FuncArgs...>,
111       internal::is_invocable<Elem<1, Tuple>, Class, FuncArgs...>,
112       internal::is_invocable<Elem<2, Tuple>, Class&, FuncArgs...>,
113       internal::is_invocable<Elem<3, Tuple>, Class, FuncArgs...>,
114       internal::is_invocable<Elem<4, Tuple>, Class&, FuncArgs...>,
115       internal::is_invocable<Elem<5, Tuple>, Class, FuncArgs...>,
116       internal::is_invocable<Elem<6, Tuple>, Class&, FuncArgs...>,
117       internal::is_invocable<Elem<7, Tuple>, Class, FuncArgs...>>::value;
118 };
119 }
120 
121 namespace
122 {
regular_function_sum(int a,int b)123 int regular_function_sum(int a, int b)
124 {
125   return a + b;
126 }
127 
128 template <unsigned int N, typename ...Args>
return_n_arg_type(Args &&...args)129 auto return_n_arg_type(Args&&... args) -> typename std::tuple_element<N, std::tuple<Args...>>::type
130 {
131   return std::get<N>(std::forward_as_tuple(std::forward<Args>(args)...));
132 }
133 
134 struct function_object_t
135 {
136   int i = 0;
137 
operator ()__anon5810dc210211::function_object_t138   int operator()(int a, int b) const
139   {
140     return a + b;
141   }
142 
mutate_data__anon5810dc210211::function_object_t143   void mutate_data()
144   {
145     i = 0;
146   }
147 };
148 
149 struct derived_function_object_t : function_object_t
150 {
151 };
152 }
153 
154 TEST_CASE("regular function")
155 {
156   using regular_function_t = decltype(regular_function_sum);
157   using regular_function_ptr_t = std::add_pointer<decltype(regular_function_sum)>::type;
158 
159   // implicit conversions work
160   static_assert(internal::is_invocable<regular_function_t, int, unsigned int>::value, "");
161   static_assert(internal::is_invocable_r<bool, regular_function_t, int, unsigned int>::value, "");
162 
163   static_assert(!internal::is_invocable<regular_function_t, int, char*>::value, "");
164   static_assert(!internal::is_invocable<regular_function_t, int, char, char>::value, "");
165   static_assert(!internal::is_invocable_r<std::string, regular_function_t, int, unsigned int>::value, "");
166 
167   static_assert(internal::is_invocable<regular_function_ptr_t, int, unsigned int>::value, "");
168   static_assert(internal::is_invocable_r<bool, regular_function_ptr_t, int, unsigned int>::value, "");
169 
170   static_assert(!internal::is_invocable<regular_function_ptr_t, int, char*>::value, "");
171   static_assert(!internal::is_invocable<regular_function_ptr_t, int, char, char>::value, "");
172   static_assert(!internal::is_invocable_r<std::string, regular_function_ptr_t, int, unsigned int>::value, "");
173 
174   REQUIRE_EQ(internal::invoke(regular_function_sum, 32, 10), 42);
175 }
176 
177 TEST_CASE("regular variadic function")
178 {
179   int i = 42;
180 
181   using variadic_function_t = decltype(return_n_arg_type<0, int&, float>);
182 
183   static_assert(internal::is_invocable<variadic_function_t, int&, float>::value, "");
184   static_assert(internal::is_invocable_r<const int&, variadic_function_t, int&, float>::value, "");
185 
186   static_assert(!internal::is_invocable<variadic_function_t, int, float>::value, "");
187   static_assert(!internal::is_invocable_r<short&, variadic_function_t, int&, float>::value, "");
188 
189   REQUIRE_EQ(std::addressof(internal::invoke(return_n_arg_type<0, int&, float>, i, 2.0f)),
190              std::addressof(i));
191 }
192 
193 TEST_CASE("function object")
194 {
195   static_assert(internal::is_invocable<function_object_t, int const&, double>::value, "");
196   static_assert(internal::is_invocable_r<int&&, function_object_t, int&, float>::value, "");
197 
198   static_assert(!internal::is_invocable<function_object_t, int, std::string>::value, "");
199   static_assert(!internal::is_invocable_r<int&, function_object_t, int, int>::value, "");
200 
201   REQUIRE_EQ(internal::invoke(function_object_t{}, 40, 2), 42);
202 }
203 
204 TEST_CASE("lambda")
205 {
__anon5810dc210302(int a, int b) 206   auto add = [](int a, int b) { return a + b; };
207 
208   using lambda_t = decltype(add);
209 
210   static_assert(internal::is_invocable<lambda_t, int const&, double>::value, "");
211   static_assert(internal::is_invocable_r<int&&, lambda_t, int&, float>::value, "");
212 
213   static_assert(!internal::is_invocable<lambda_t, int, std::string>::value, "");
214   static_assert(!internal::is_invocable_r<int&, lambda_t, int, int>::value, "");
215 
216   REQUIRE_EQ(internal::invoke(add, 40, 2), 42);
217 }
218 
219 TEST_CASE("member function - object reference")
220 {
221   using call_operator_t = decltype(&function_object_t::operator());
222   using mutate_data_t = decltype(&function_object_t::mutate_data);
223 
224   auto qualifiers =
225       all_qualifiers(identity<int (function_object_t::*)(int, int)>{});
226   static_assert(all_invocable<decltype(qualifiers), function_object_t, int const&, double>::value, "");
227 
228   static_assert(internal::is_invocable<call_operator_t, function_object_t, int const&, double>::value, "");
229   static_assert(internal::is_invocable<mutate_data_t, function_object_t>::value, "");
230   static_assert(internal::is_invocable_r<int&&, call_operator_t, function_object_t, int&, float>::value, "");
231 
232   // non-const member function
233   static_assert(internal::is_invocable<mutate_data_t, function_object_t&>::value, "");
234   static_assert(!internal::is_invocable<mutate_data_t, const function_object_t&>::value, "");
235 
236   static_assert(!internal::is_invocable_r<int&, call_operator_t, function_object_t, int, int>::value, "");
237 
238   auto adder = function_object_t{};
239   REQUIRE_EQ(internal::invoke(&function_object_t::operator(), adder, 40, 2), 42);
240 }
241 
242 TEST_CASE("member function - reference_wrapper<object>")
243 {
244   using call_operator_t = decltype(&function_object_t::operator());
245   using mutate_data_t = decltype(&function_object_t::mutate_data);
246   using ref_wrapper_t = std::reference_wrapper<function_object_t>;
247   using ref_wrapper_const_t = std::reference_wrapper<const function_object_t>;
248 
249   static_assert(internal::is_invocable<call_operator_t, ref_wrapper_t, int const&, double>::value, "");
250   static_assert(internal::is_invocable<call_operator_t, ref_wrapper_const_t, int const&, double>::value, "");
251   static_assert(internal::is_invocable_r<int&&, call_operator_t, ref_wrapper_t, int&, float>::value, "");
252   static_assert(internal::is_invocable_r<int&&, call_operator_t, ref_wrapper_const_t, int&, float>::value, "");
253 
254   // non-const member function
255   static_assert(internal::is_invocable<mutate_data_t, ref_wrapper_t>::value, "");
256   static_assert(!internal::is_invocable<mutate_data_t, ref_wrapper_const_t>::value, "");
257 
258   static_assert(!internal::is_invocable_r<int&, call_operator_t, ref_wrapper_t, int, int>::value, "");
259 
260   auto adder = function_object_t{};
261   REQUIRE_EQ(internal::invoke(&function_object_t::operator(), std::ref(adder), 40, 2), 42);
262   REQUIRE_EQ(internal::invoke(&function_object_t::operator(), std::cref(adder), 40, 2), 42);
263 }
264 
265 TEST_CASE("member function - object pointer")
266 {
267   using call_operator_t = decltype(&function_object_t::operator());
268   using mutate_data_t = decltype(&function_object_t::mutate_data);
269 
270   static_assert(internal::is_invocable<call_operator_t, function_object_t*, int const&, double>::value, "");
271   static_assert(internal::is_invocable_r<int&&, call_operator_t, function_object_t*, int&, float>::value, "");
272 
273   // non-const member function
274   static_assert(internal::is_invocable<mutate_data_t, function_object_t*>::value, "");
275   static_assert(!internal::is_invocable<mutate_data_t, const function_object_t*>::value, "");
276 
277   static_assert(!internal::is_invocable_r<int&, call_operator_t, function_object_t*, int, int>::value, "");
278 
279   auto adder = function_object_t{};
280   REQUIRE_EQ(internal::invoke(&function_object_t::operator(), &adder, 40, 2), 42);
281 }
282 
283 TEST_CASE("member function - derived object reference")
284 {
285   using call_operator_t = decltype(&function_object_t::operator());
286   using mutate_data_t = decltype(&function_object_t::mutate_data);
287 
288   // should split all_qualifiers to get specific ones, right now it cannot
289   // be used to test const objects and reference_wrapper.
290   // Need to add make_index_sequence to do that properly.
291   auto qualifiers =
292       all_qualifiers(identity<int (function_object_t::*)(int, int)>{});
293 #if !defined(FPLUS_MSVC2015_BYPASS_FAILING_TESTS) // Error C2338 under MSVC (i.e static_assert fail)
294   static_assert(all_invocable<decltype(qualifiers), derived_function_object_t, int const&, double>::value, "");
295 #endif
296 
297   static_assert(internal::is_invocable<call_operator_t, derived_function_object_t, int const&, double>::value, "");
298   static_assert(internal::is_invocable_r<int&&, call_operator_t, derived_function_object_t, int&, float>::value, "");
299 
300   // non-const member function
301   static_assert(internal::is_invocable<mutate_data_t, derived_function_object_t&>::value, "");
302   static_assert(!internal::is_invocable<mutate_data_t, const derived_function_object_t&>::value, "");
303 
304   static_assert(!internal::is_invocable_r<int&, call_operator_t, derived_function_object_t&, int, int>::value, "");
305 
306   auto adder = derived_function_object_t{};
307   REQUIRE_EQ(internal::invoke(&function_object_t::operator(), adder, 40, 2), 42);
308 }
309 
310 TEST_CASE("member function - reference_wrapper<derived object>")
311 {
312   using call_operator_t = decltype(&function_object_t::operator());
313   using mutate_data_t = decltype(&function_object_t::mutate_data);
314 
315   using ref_wrapper_t = std::reference_wrapper<derived_function_object_t>;
316   using ref_wrapper_const_t = std::reference_wrapper<const derived_function_object_t>;
317 
318   static_assert(internal::is_invocable<call_operator_t, ref_wrapper_t, int const&, double>::value, "");
319   static_assert(internal::is_invocable<call_operator_t, ref_wrapper_const_t, int const&, double>::value, "");
320   static_assert(internal::is_invocable_r<int&&, call_operator_t, ref_wrapper_t, int&, float>::value, "");
321 
322   // non-const member function
323   static_assert(internal::is_invocable<mutate_data_t, ref_wrapper_t>::value, "");
324   static_assert(!internal::is_invocable<mutate_data_t, ref_wrapper_const_t>::value, "");
325 
326   static_assert(!internal::is_invocable_r<int&, call_operator_t, ref_wrapper_t&, int, int>::value, "");
327 
328   auto adder = derived_function_object_t{};
329   REQUIRE_EQ(internal::invoke(&function_object_t::operator(), adder, 40, 2), 42);
330 }
331 
332 TEST_CASE("member function - derived object pointer")
333 {
334   using call_operator_t = decltype(&function_object_t::operator());
335   using mutate_data_t = decltype(&function_object_t::mutate_data);
336 
337   static_assert(internal::is_invocable<call_operator_t, derived_function_object_t*, int const&, double>::value, "");
338   static_assert(internal::is_invocable_r<int&&, call_operator_t, derived_function_object_t*, int&, float>::value, "");
339 
340   // non-const non-volatile member function
341   static_assert(internal::is_invocable<mutate_data_t, derived_function_object_t*>::value, "");
342   static_assert(!internal::is_invocable<mutate_data_t, const derived_function_object_t*>::value, "");
343   static_assert(!internal::is_invocable<mutate_data_t, volatile derived_function_object_t*>::value, "");
344 
345   static_assert(!internal::is_invocable_r<int&, call_operator_t, derived_function_object_t*, int, int>::value, "");
346 
347   auto adder = derived_function_object_t{};
348   REQUIRE_EQ(internal::invoke(&function_object_t::operator(), &adder, 40, 2), 42);
349 }
350 
351 TEST_CASE("member data - object reference")
352 {
353   using member_data_t = decltype(&function_object_t::i);
354 
355   static_assert(internal::is_invocable<member_data_t, function_object_t>::value, "");
356   static_assert(internal::is_invocable_r<int&&, member_data_t, function_object_t>::value, "");
357 
358   // cannot convert lvalue ref to rvalue-reference
359   static_assert(!internal::is_invocable_r<int&&, member_data_t, function_object_t&>::value, "");
360 
361   static_assert(!internal::is_invocable<member_data_t, function_object_t, int>::value, "");
362 
363   auto obj = function_object_t{};
364   obj.i = 42;
365   REQUIRE_EQ(internal::invoke(&function_object_t::i, obj), 42);
366 }
367 
368 TEST_CASE("member data - reference_wrapper<object>")
369 {
370   using member_data_t = decltype(&function_object_t::i);
371   using ref_wrapper_t = std::reference_wrapper<function_object_t>;
372   using ref_wrapper_const_t = std::reference_wrapper<const function_object_t>;
373 
374   static_assert(internal::is_invocable<member_data_t, ref_wrapper_t>::value, "");
375   static_assert(internal::is_invocable_r<int const&, member_data_t, ref_wrapper_const_t>::value, "");
376 
377   // cannot convert lvalue ref to rvalue-reference
378   static_assert(!internal::is_invocable_r<int&&, member_data_t, ref_wrapper_t>::value, "");
379   // nor from const lvalue reference to non-const lvalue reference
380   static_assert(!internal::is_invocable_r<int&, member_data_t, ref_wrapper_const_t>::value, "");
381 
382   auto obj = function_object_t{};
383   obj.i = 42;
384 
385   REQUIRE_EQ(internal::invoke(&function_object_t::i, std::ref(obj)), 42);
386   REQUIRE_EQ(internal::invoke(&function_object_t::i, std::cref(obj)), 42);
387 }
388 
389 TEST_CASE("member data - object pointer")
390 {
391   using member_data_t = decltype(&function_object_t::i);
392 
393   static_assert(internal::is_invocable<member_data_t, function_object_t*>::value, "");
394   static_assert(internal::is_invocable_r<int&, member_data_t, function_object_t*>::value, "");
395 
396   // cannot convert lvalue ref to rvalue-reference
397   static_assert(!internal::is_invocable_r<int&&, member_data_t, function_object_t*>::value, "");
398   static_assert(!internal::is_invocable_r<int&, member_data_t, const function_object_t*>::value, "");
399 
400   static_assert(!internal::is_invocable<member_data_t, function_object_t*, int>::value, "");
401 
402   auto obj = function_object_t{};
403   obj.i = 42;
404   REQUIRE_EQ(internal::invoke(&function_object_t::i, &obj), 42);
405 }
406 
407 TEST_CASE("member data - derived object reference")
408 {
409   using member_data_t = decltype(&function_object_t::i);
410 
411   static_assert(internal::is_invocable<member_data_t, derived_function_object_t>::value, "");
412   static_assert(internal::is_invocable_r<int&&, member_data_t, derived_function_object_t>::value, "");
413 
414   // cannot convert lvalue ref to rvalue-reference
415   static_assert(!internal::is_invocable_r<int&&, member_data_t, derived_function_object_t&>::value, "");
416 
417   static_assert(!internal::is_invocable<member_data_t, derived_function_object_t, int>::value, "");
418 
419   auto obj = derived_function_object_t{};
420   obj.i = 42;
421   REQUIRE_EQ(internal::invoke(&function_object_t::i, obj), 42);
422 }
423 
424 TEST_CASE("member data - reference_wrapper<derived object>")
425 {
426   using member_data_t = decltype(&function_object_t::i);
427 
428   using ref_wrapper_t = std::reference_wrapper<derived_function_object_t>;
429   using ref_wrapper_const_t = std::reference_wrapper<const derived_function_object_t>;
430 
431   static_assert(internal::is_invocable<member_data_t, ref_wrapper_t>::value, "");
432   static_assert(internal::is_invocable_r<int const&, member_data_t, ref_wrapper_const_t>::value, "");
433 
434   // cannot convert lvalue ref to rvalue-reference
435   static_assert(!internal::is_invocable_r<int&&, member_data_t, ref_wrapper_t>::value, "");
436   // nor from const lvalue reference to non-const lvalue reference
437   static_assert(!internal::is_invocable_r<int&, member_data_t, ref_wrapper_const_t>::value, "");
438 
439   auto obj = derived_function_object_t{};
440   obj.i = 42;
441 
442   REQUIRE_EQ(internal::invoke(&function_object_t::i, std::ref(obj)), 42);
443   REQUIRE_EQ(internal::invoke(&function_object_t::i, std::cref(obj)), 42);
444 }
445 
446 TEST_CASE("member data - derived object pointer")
447 {
448   using member_data_t = decltype(&function_object_t::i);
449 
450   static_assert(internal::is_invocable<member_data_t, derived_function_object_t*>::value, "");
451   static_assert(internal::is_invocable_r<int&, member_data_t, derived_function_object_t*>::value, "");
452 
453   // cannot convert lvalue ref to rvalue-reference
454   static_assert(!internal::is_invocable_r<int&&, member_data_t, derived_function_object_t*>::value, "");
455   static_assert(!internal::is_invocable_r<int&, member_data_t, const derived_function_object_t*>::value, "");
456 
457   static_assert(!internal::is_invocable<member_data_t, derived_function_object_t*, int>::value, "");
458 
459   auto obj = derived_function_object_t{};
460   obj.i = 42;
461   REQUIRE_EQ(internal::invoke(&derived_function_object_t::i, &obj), 42);
462 }
463 
464 #ifdef __GNUC__
465 #pragma GCC diagnostic push
466 #pragma GCC diagnostic ignored "-Wconversion"
467 #endif // __GNUC__
468 TEST_CASE("generic lambda")
469 {
__anon5810dc210402(auto a, auto b) 470   auto add = [](auto a, auto b) { return a + b; };
471 
472   using lambda_t = decltype(add);
473 
474   static_assert(internal::is_invocable<lambda_t, int const&, double>::value, "");
475   static_assert(internal::is_invocable_r<int&&, lambda_t, int&, float>::value, "");
476 
477   // compile error, static_assert doesn't trigger though
478   // from cppreference:
479   //
480   // Formally, determines whether INVOKE(declval<Fn>(),
481   // declval<ArgTypes>()...) is well formed when treated as an unevaluated
482   // operand, where INVOKE is the operation defined in Callable.
483   //
484   // This is indeed well-formed in the unevaluated context...
485   // static_assert(!internal::is_invocable<lambda_t, int, std::string>::value, "");
486 
487   static_assert(!internal::is_invocable_r<int&, lambda_t, int, int>::value, "");
488 
489   REQUIRE_EQ(internal::invoke(add, 40, 2), 42);
490 }
491 
492 TEST_CASE("transparent function objects")
493 {
494   static_assert(internal::is_invocable<std::plus<>, int, int>::value, "");
495   static_assert(internal::is_invocable<std::plus<>, int, float>::value, "");
496 
497   REQUIRE_EQ(internal::invoke(std::plus<>{}, 40, 2), 42);
498 }
499 
500 #ifdef __GNUC__
501 #pragma GCC diagnostic pop
502 #endif // __GNUC__
503