1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
// Copyright 2025 Steven Le Rouzic
//
// SPDX-License-Identifier: BSD-3-Clause
#pragma once
#include "asl/base/meta.hpp"
#include "asl/base/utility.hpp"
namespace asl {
template<typename F, typename... Args>
constexpr auto invoke(F&& f, Args&&... args)
-> decltype(std::forward<F>(f)(std::forward<Args>(args)...))
requires (!is_member_ptr<un_cvref_t<F>>) && requires {
f(std::forward<Args>(args)...);
}
{
return std::forward<F>(f)(std::forward<Args>(args)...);
}
template<typename C>
constexpr auto&& invoke(auto C::* f, same_or_derived_from<C> auto&& arg)
{
return std::forward<decltype(arg)>(arg).*f;
}
template<typename C>
constexpr auto&& invoke(auto C::* f, auto&& arg)
requires (
!same_or_derived_from<decltype(arg), C>
&& requires { (*arg).*f; }
)
{
return (*std::forward<decltype(arg)>(arg)).*f;
}
template<typename C, typename... Args>
constexpr auto invoke(is_func auto C::* f, same_or_derived_from<C> auto&& self, Args&&... args)
-> decltype((std::forward<decltype(self)>(self).*f)(std::forward<Args>(args)...))
requires requires { (self.*f)(std::forward<Args>(args)...); }
{
return (std::forward<decltype(self)>(self).*f)(std::forward<Args>(args)...);
}
template<typename C, typename... Args>
constexpr auto invoke(is_func auto C::* f, auto&& self, Args&&... args)
-> decltype(((*std::forward<decltype(self)>(self)).*f)(std::forward<Args>(args)...))
requires (
!same_or_derived_from<decltype(self), C>
&& requires { ((*self).*f)(std::forward<Args>(args)...); }
)
{
return ((*std::forward<decltype(self)>(self)).*f)(std::forward<Args>(args)...);
}
template<typename R, typename F, typename... Args>
constexpr R invoke_r(F&& f, Args&&... args)
{
if constexpr (is_void<R>)
{
static_cast<void>(invoke(std::forward<F>(f), std::forward<Args>(args)...));
}
else
{
return invoke(std::forward<F>(f), std::forward<Args>(args)...);
}
}
template<typename Void, typename F, typename... Args>
struct _invoke_result_helper;
template<typename R, typename... Args>
struct _invoke_result_helper<void, R, Args...>
{
using type = decltype(invoke(declval<R>(), declval<Args>()...));
};
template<typename F, typename... Args>
using invoke_result_t = _invoke_result_helper<void, F, Args...>::type;
template<typename F, typename... Args>
concept invocable = requires (F&& f, Args&&... args)
{
invoke(std::forward<F>(f), std::forward<Args>(args)...);
};
template<typename R, typename F, typename... Args>
concept invocable_r = invocable<F, Args...>
&& (is_void<R> || convertible_to<invoke_result_t<F, Args...>, R>);
} // namespace asl
|