|
5 | 5 |
|
6 | 6 | #include "is_reference_wrapper.hpp" |
7 | 7 |
|
8 | | -template<bool /* std::is_member_pointer */> |
9 | | -struct InvokeSelector { |
10 | | - template<class Base, class T, class Derived, class... Args> |
11 | | - static constexpr auto call(T Base::*pmf, Derived&& ref, Args&&... args) |
12 | | - -> std::enable_if_t<std::is_function_v<T> && |
13 | | - std::is_base_of_v<Base, std::decay_t<Derived>>, |
14 | | - decltype((std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...))> |
15 | | - { return (std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...); } |
16 | | - |
17 | | - template<class Base, class T, class RefWrap, class... Args> |
18 | | - static constexpr auto call(T Base::*pmf, RefWrap&& ref, Args&&... args) |
19 | | - -> std::enable_if_t<std::is_function_v<T> && |
20 | | - is_reference_wrapper_v<std::decay_t<RefWrap>>, |
21 | | - decltype((ref.get().*pmf)(std::forward<Args>(args)...))> |
22 | | - { return (ref.get().*pmf)(std::forward<Args>(args)...); } |
| 8 | +template<class> |
| 9 | +struct invoke_impl { |
| 10 | + template<class F, class... Args> |
| 11 | + static constexpr auto call(F&& f, Args&&... args) |
| 12 | + noexcept(noexcept(static_cast<F&&>(f)(static_cast<Args&&>(args)...))) |
| 13 | + -> decltype(static_cast<F&&>(f)(static_cast<Args&&>(args)...)) |
| 14 | + { return static_cast<F&&>(f)(static_cast<Args&&>(args)...); } |
| 15 | +}; |
23 | 16 |
|
24 | | - template<class Base, class T, class Pointer, class... Args> |
25 | | - static constexpr auto call(T Base::*pmf, Pointer&& ptr, Args&&... args) |
26 | | - -> std::enable_if_t<std::is_function_v<T> && |
27 | | - !is_reference_wrapper_v<std::decay_t<Pointer>> && |
28 | | - !std::is_base_of_v<Base, std::decay_t<Pointer>>, |
29 | | - decltype(((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...))> |
30 | | - { return ((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...); } |
| 17 | +template<class A, class B> |
| 18 | +struct invoke_impl<A B::*> { |
| 19 | + template<class T, |
| 20 | + class = std::enable_if_t<std::is_base_of_v<B, std::decay_t<T>>> |
| 21 | + > |
| 22 | + static constexpr auto get(T&& t) |
| 23 | + noexcept(noexcept(static_cast<T&&>(t))) |
| 24 | + -> decltype(static_cast<T&&>(t)) |
| 25 | + { return static_cast<T&&>(t); } |
31 | 26 |
|
32 | | - template<class Base, class T, class Derived> |
33 | | - static constexpr auto call(T Base::*pmd, Derived&& ref) |
34 | | - -> std::enable_if_t<!std::is_function_v<T> && |
35 | | - std::is_base_of_v<Base, std::decay_t<Derived>>, |
36 | | - decltype(std::forward<Derived>(ref).*pmd)> |
37 | | - { return std::forward<Derived>(ref).*pmd; } |
| 27 | + template<class T, |
| 28 | + class = std::enable_if_t<is_reference_wrapper_v<std::decay_t<T>>> |
| 29 | + > |
| 30 | + static constexpr auto get(T&& t) |
| 31 | + noexcept(noexcept(t.get())) |
| 32 | + -> decltype(t.get()) |
| 33 | + { return t.get(); } |
38 | 34 |
|
39 | | - template<class Base, class T, class RefWrap> |
40 | | - static constexpr auto call(T Base::*pmd, RefWrap&& ref) |
41 | | - -> std::enable_if_t<!std::is_function_v<T> && |
42 | | - is_reference_wrapper_v<std::decay_t<RefWrap>>, |
43 | | - decltype(ref.get().*pmd)> |
44 | | - { return ref.get().*pmd; } |
| 35 | + template<class T, |
| 36 | + class = std::enable_if_t<!std::is_base_of_v<B, std::decay_t<T>>>, |
| 37 | + class = std::enable_if_t<!is_reference_wrapper_v<std::decay_t<T>>> |
| 38 | + > |
| 39 | + static constexpr auto get(T&& t) |
| 40 | + noexcept(noexcept(*static_cast<T&&>(t))) |
| 41 | + -> decltype(*static_cast<T&&>(t)) |
| 42 | + { return *static_cast<T&&>(t); } |
45 | 43 |
|
46 | | - template<class Base, class T, class Pointer> |
47 | | - static constexpr auto call(T Base::*pmd, Pointer&& ptr) |
48 | | - -> std::enable_if_t<!std::is_function_v<T> && |
49 | | - !is_reference_wrapper_v<std::decay_t<Pointer>> && |
50 | | - !std::is_base_of_v<Base, std::decay_t<Pointer>>, |
51 | | - decltype((*std::forward<Pointer>(ptr)).*pmd)> |
52 | | - { return (*std::forward<Pointer>(ptr)).*pmd; } |
53 | | -}; |
| 44 | + template<class AA, class T, class... Args, |
| 45 | + class = std::enable_if_t<std::is_function_v<AA>> |
| 46 | + > |
| 47 | + static constexpr auto call(AA B::*pmf, T&& t, Args&&... args) |
| 48 | + noexcept(noexcept(((get)(static_cast<T&&>(t)).*pmf)(static_cast<Args&&>(args)...))) |
| 49 | + -> decltype(((get)(static_cast<T&&>(t)).*pmf)(static_cast<Args&&>(args)...)) |
| 50 | + { return ((get)(static_cast<T&&>(t)).*pmf)(static_cast<Args&&>(args)...); } |
54 | 51 |
|
55 | | -template<> |
56 | | -struct InvokeSelector<false> { |
57 | | - template<class F, class... Args> |
58 | | - static constexpr auto call(F&& f, Args&&... args) |
59 | | - -> decltype(std::forward<F>(f)(std::forward<Args>(args)...)) |
60 | | - { return std::forward<F>(f)(std::forward<Args>(args)...); } |
| 52 | + template<class T> |
| 53 | + static constexpr auto call(A B::*pmd, T&& t) |
| 54 | + noexcept(noexcept((get)(static_cast<T&&>(t)).*pmd)) |
| 55 | + -> decltype((get)(static_cast<T&&>(t)).*pmd) |
| 56 | + { return (get)(static_cast<T&&>(t)).*pmd; } |
61 | 57 | }; |
62 | 58 |
|
63 | | -template<class F, class... ArgTypes> |
64 | | -constexpr auto invoke(F&& f, ArgTypes&&... args) |
65 | | - -> decltype( |
66 | | - InvokeSelector<std::is_member_pointer_v<std::decay_t<F>>>::call( |
67 | | - std::forward<F>(f), std::forward<ArgTypes>(args)...) |
68 | | - ) |
| 59 | +template<class F, class... Args> |
| 60 | +constexpr auto invoke(F&& f, Args&&... args) |
| 61 | + noexcept(noexcept(invoke_impl<std::decay_t<F>>::call( |
| 62 | + static_cast<F&&>(f), static_cast<Args&&>(args)...))) |
| 63 | + -> decltype(invoke_impl<std::decay_t<F>>::call( |
| 64 | + static_cast<F&&>(f), static_cast<Args&&>(args)...)) |
69 | 65 | { |
70 | | - return InvokeSelector<std::is_member_pointer_v<std::decay_t<F>>>::call( |
71 | | - std::forward<F>(f), std::forward<ArgTypes>(args)...); |
| 66 | + return invoke_impl<std::decay_t<F>>::call( |
| 67 | + static_cast<F&&>(f), static_cast<Args&&>(args)...); |
72 | 68 | } |
73 | 69 |
|
74 | | -template<class R, class F, class... ArgTypes, |
75 | | - std::enable_if_t<!std::is_void_v<R>, int> = 0, |
76 | | - std::enable_if_t< |
77 | | - std::is_convertible_v< |
78 | | - decltype( |
79 | | - InvokeSelector<std::is_member_pointer_v<std::decay_t<F>>>::call( |
80 | | - std::declval<F>(), std::declval<ArgTypes>()...)), |
81 | | - R |
82 | | - >, |
83 | | - int> = 0 |
| 70 | +template<class T> |
| 71 | +void implicit_cast(T) noexcept; |
| 72 | + |
| 73 | +template<class R, class F, class... Args, |
| 74 | + class = std::enable_if_t<!std::is_void_v<R>>, |
| 75 | + class = decltype((implicit_cast<R>)( |
| 76 | + invoke_impl<std::decay_t<F>>::call( |
| 77 | + std::declval<F>(), std::declval<Args>()...))) |
84 | 78 | > |
85 | | -constexpr R invoke(F&& f, ArgTypes&&... args) { |
86 | | - return InvokeSelector<std::is_member_pointer_v<std::decay_t<F>>>::call( |
87 | | - std::forward<F>(f), std::forward<ArgTypes>(args)...); |
| 79 | +constexpr R invoke(F&& f, Args&&... args) |
| 80 | + noexcept(noexcept((implicit_cast<R>)( |
| 81 | + invoke_impl<std::decay_t<F>>::call( |
| 82 | + static_cast<F&&>(f), static_cast<Args&&>(args)...)))) |
| 83 | +{ |
| 84 | + return invoke_impl<std::decay_t<F>>::call( |
| 85 | + static_cast<F&&>(f), static_cast<Args&&>(args)...); |
88 | 86 | } |
89 | 87 |
|
90 | | -template<class R, class F, class... ArgTypes, |
91 | | - std::enable_if_t<std::is_void_v<R>, int> = 0, |
92 | | - decltype((void)InvokeSelector<std::is_member_pointer_v<std::decay_t<F>>>::call( |
93 | | - std::declval<F>(), std::declval<ArgTypes>()...), 0) = 0 |
| 88 | +template<class R, class F, class... Args, |
| 89 | + class = std::enable_if_t<std::is_void_v<R>>, |
| 90 | + class = decltype(invoke_impl<std::decay_t<F>>::call( |
| 91 | + std::declval<F>(), std::declval<Args>()...)) |
94 | 92 | > |
95 | | -constexpr void invoke(F&& f, ArgTypes&&... args) { |
96 | | - InvokeSelector<std::is_member_pointer_v<F>>::call( |
97 | | - std::forward<F>(f), std::forward<ArgTypes>(args)...); |
| 93 | +constexpr void invoke(F&& f, Args&&... args) |
| 94 | + noexcept(noexcept(invoke_impl<std::decay_t<F>>::call( |
| 95 | + static_cast<F&&>(f), static_cast<Args&&>(args)...))) |
| 96 | +{ |
| 97 | + invoke_impl<std::decay_t<F>>::call( |
| 98 | + static_cast<F&&>(f), static_cast<Args&&>(args)...); |
98 | 99 | } |
0 commit comments