Skip to content

Commit 130d707

Browse files
authored
Update invoke.hpp
1 parent 7ae5369 commit 130d707

1 file changed

Lines changed: 77 additions & 76 deletions

File tree

invoke.hpp

Lines changed: 77 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -5,94 +5,95 @@
55

66
#include "is_reference_wrapper.hpp"
77

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+
};
2316

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); }
3126

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(); }
3834

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); }
4543

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)...); }
5451

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; }
6157
};
6258

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)...))
6965
{
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)...);
7268
}
7369

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>()...)))
8478
>
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)...);
8886
}
8987

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>()...))
9492
>
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)...);
9899
}

0 commit comments

Comments
 (0)