Skip to content

Commit 0a964c7

Browse files
authored
Merge pull request #282 from elbeno/freestanding-func-traits
🎨 Make `function_traits` available in freestanding
2 parents 7fcc96f + 9328649 commit 0a964c7

File tree

9 files changed

+294
-28
lines changed

9 files changed

+294
-28
lines changed

.github/workflows/asciidoctor-ghpages.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242

4343
- name: Install Mermaid
4444
run: |
45-
npm install -g @mermaid-js/mermaid-cli@11.4.2
45+
npm install -g @mermaid-js/mermaid-cli@11.12.0
4646
npx puppeteer browsers install chrome-headless-shell
4747
4848
- name: Install asciidoctor

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ build/
33
/venv
44
/.vscode
55
/.idea
6-
/.cache
6+
.cache/
77
/.DS_Store
88
.clang-format
99
.clang-tidy

docs/for_each_n_args.adoc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ https://github.com/intel/cpp-std-extensions/blob/main/include/stdx/for_each_n_ar
55
provides a method for calling a function (or other callable) with batches of
66
arguments from a parameter pack.
77

8-
IMPORTANT: `for_each_n_args` is not yet available on freestanding implementations.
9-
108
Examples:
119
[source,cpp]
1210
----

docs/function_traits.adoc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ https://github.com/intel/cpp-std-extensions/blob/main/include/stdx/function_trai
55
contains type traits for introspecting function signatures. It works with
66
functions, lambda expressions, and classes with `operator()`.
77

8-
IMPORTANT: Function traits are not yet available on freestanding implementations.
9-
108
Examples:
119
[source,cpp]
1210
----

include/stdx/bit.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,8 +438,7 @@ template <std::size_t N> using smallest_uint_t = decltype(smallest_uint<N>());
438438

439439
namespace bit_detail {
440440
template <std::size_t... Offsets>
441-
constexpr auto shifts =
442-
[]() -> std::array<std::size_t, sizeof...(Offsets) + 1> {
441+
constexpr auto shifts = []()->std::array<std::size_t, sizeof...(Offsets) + 1> {
443442
constexpr auto offsets = std::array{std::size_t{}, Offsets...};
444443
auto s = std::array<std::size_t, sizeof...(Offsets) + 1>{};
445444
for (auto i = std::size_t{}; i < sizeof...(Offsets); ++i) {

include/stdx/function_traits.hpp

Lines changed: 113 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,136 @@
55
#include <boost/mp11/algorithm.hpp>
66
#include <boost/mp11/utility.hpp>
77

8-
#include <functional>
98
#include <type_traits>
109
#include <utility>
1110

1211
namespace stdx {
1312
inline namespace v1 {
1413
namespace detail {
15-
template <typename...> struct function_traits;
14+
template <auto> struct any_type {
15+
// NOLINTNEXTLINE(google-explicit-constructor)
16+
template <typename T> operator T();
17+
};
1618

17-
template <typename R, typename... Args>
18-
struct function_traits<std::function<R(Args...)>> {
19+
template <typename F> struct function_traits;
20+
21+
template <typename R, typename... Args> struct function_traits<R(Args...)> {
1922
using return_type = R;
2023

2124
template <template <typename...> typename List> using args = List<Args...>;
2225
template <template <typename...> typename List>
2326
using decayed_args = List<std::decay_t<Args>...>;
2427
using arity = std::integral_constant<std::size_t, sizeof...(Args)>;
28+
using obj_t = void;
2529

2630
template <auto N> using nth_arg = nth_t<N, Args...>;
2731
template <auto N> using decayed_nth_arg = std::decay_t<nth_arg<N>>;
32+
33+
template <std::size_t... Is>
34+
constexpr static auto invoke(std::index_sequence<Is...>)
35+
-> std::invoke_result_t<R(Args...), any_type<Is>...>;
36+
};
37+
38+
template <typename R, typename... Args>
39+
struct function_traits<R (*)(Args...)> : function_traits<R(Args...)> {};
40+
41+
template <typename R, typename... Args>
42+
struct function_traits<R (*const)(Args...)> : function_traits<R(Args...)> {};
43+
44+
template <typename R, typename... Args>
45+
struct function_traits<R (*volatile)(Args...)> : function_traits<R(Args...)> {};
46+
47+
template <typename R, typename... Args>
48+
struct function_traits<R (*const volatile)(Args...)>
49+
: function_traits<R(Args...)> {};
50+
51+
template <typename C, typename R, typename... Args>
52+
struct function_traits<R (C::*)(Args...)> : function_traits<R(Args...)> {
53+
using obj_t = C;
54+
};
55+
56+
template <typename C, typename R, typename... Args>
57+
struct function_traits<R (C::*)(Args...) &> : function_traits<R(Args...)> {
58+
using obj_t = C &;
59+
};
60+
61+
template <typename C, typename R, typename... Args>
62+
struct function_traits<R (C::*)(Args...) const &>
63+
: function_traits<R(Args...)> {
64+
using obj_t = C const &;
65+
};
66+
67+
template <typename C, typename R, typename... Args>
68+
struct function_traits<R (C::*)(Args...) volatile &>
69+
: function_traits<R(Args...)> {
70+
using obj_t = C volatile &;
71+
};
72+
73+
template <typename C, typename R, typename... Args>
74+
struct function_traits<R (C::*)(Args...) const volatile &>
75+
: function_traits<R(Args...)> {
76+
using obj_t = C const volatile &;
77+
};
78+
79+
template <typename C, typename R, typename... Args>
80+
struct function_traits<R (C::*)(Args...) &&> : function_traits<R(Args...)> {
81+
using obj_t = C &&;
82+
};
83+
84+
template <typename C, typename R, typename... Args>
85+
struct function_traits<R (C::*)(Args...) const &&>
86+
: function_traits<R(Args...)> {
87+
using obj_t = C const &&;
88+
};
89+
90+
template <typename C, typename R, typename... Args>
91+
struct function_traits<R (C::*)(Args...) volatile &&>
92+
: function_traits<R(Args...)> {
93+
using obj_t = C volatile &&;
94+
};
95+
96+
template <typename C, typename R, typename... Args>
97+
struct function_traits<R (C::*)(Args...) const volatile &&>
98+
: function_traits<R(Args...)> {
99+
using obj_t = C const volatile &&;
100+
};
101+
102+
template <typename C, typename R, typename... Args>
103+
struct function_traits<R (C::*)(Args...) const> : function_traits<R(Args...)> {
104+
using obj_t = C const;
105+
};
106+
107+
template <typename C, typename R, typename... Args>
108+
struct function_traits<R (C::*)(Args...) volatile>
109+
: function_traits<R(Args...)> {
110+
using obj_t = C volatile;
28111
};
29-
} // namespace detail
30112

113+
template <typename C, typename R, typename... Args>
114+
struct function_traits<R (C::*)(Args...) const volatile>
115+
: function_traits<R(Args...)> {
116+
using obj_t = C const volatile;
117+
};
118+
119+
template <typename F, typename = void> struct detect_call_operator {
120+
template <std::size_t... Is>
121+
constexpr static auto invoke(std::index_sequence<Is...>) ->
122+
typename boost::mp11::mp_cond<
123+
boost::mp11::mp_valid<std::invoke_result_t, F &&, any_type<Is>...>,
124+
boost::mp11::mp_defer<std::invoke_result_t, F &&, any_type<Is>...>,
125+
boost::mp11::mp_valid<std::invoke_result_t, F &, any_type<Is>...>,
126+
boost::mp11::mp_defer<std::invoke_result_t, F &,
127+
any_type<Is>...>>::type;
128+
};
31129
template <typename F>
32-
using function_traits =
33-
detail::function_traits<decltype(std::function{std::declval<F>()})>;
130+
struct detect_call_operator<
131+
F, std::void_t<decltype(&remove_cvref_t<F>::operator())>>
132+
: function_traits<decltype(&remove_cvref_t<F>::operator())> {};
133+
134+
template <typename F> struct function_traits : detect_call_operator<F> {};
135+
} // namespace detail
136+
137+
template <typename F> using function_traits = detail::function_traits<F>;
34138

35139
template <typename F> using return_t = typename function_traits<F>::return_type;
36140
template <typename F, template <typename...> typename List>
@@ -39,6 +143,7 @@ template <typename F, template <typename...> typename List>
39143
using decayed_args_t = typename function_traits<F>::template decayed_args<List>;
40144
template <typename F>
41145
using nongeneric_arity_t = typename function_traits<F>::arity;
146+
template <typename F> using obj_arg_t = typename function_traits<F>::obj_t;
42147

43148
template <typename F, auto N>
44149
using nth_arg_t = typename function_traits<F>::template nth_arg<N>;
@@ -47,18 +152,9 @@ using decayed_nth_arg_t =
47152
typename function_traits<F>::template decayed_nth_arg<N>;
48153

49154
namespace detail {
50-
template <auto> struct any_type {
51-
// NOLINTNEXTLINE(google-explicit-constructor)
52-
template <typename T> operator T();
53-
};
54-
55-
template <typename F, std::size_t... Is>
56-
constexpr auto try_invoke_impl(std::index_sequence<Is...>)
57-
-> std::invoke_result_t<F, any_type<Is>...>;
58-
59155
template <typename F, typename N>
60156
using try_invoke =
61-
decltype(try_invoke_impl<F>(std::make_index_sequence<N::value>{}));
157+
decltype(function_traits<F>::invoke(std::make_index_sequence<N::value>{}));
62158

63159
template <typename F, typename N>
64160
using has_arg_count = boost::mp11::mp_valid<try_invoke, F, N>;

include/stdx/tuple_algorithms.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ constexpr auto contains_type(
230230
template <tuplelike T, template <typename> typename Proj = std::type_identity_t>
231231
[[nodiscard]] constexpr auto sorted_indices() {
232232
return []<std::size_t... Is>(std::index_sequence<Is...>)
233-
-> std::array<std::size_t, sizeof...(Is)> {
233+
->std::array<std::size_t, sizeof...(Is)> {
234234
using P = std::pair<std::string_view, std::size_t>;
235235
auto a = std::array<P, sizeof...(Is)>{
236236
P{stdx::type_as_string<Proj<tuple_element_t<Is, T>>>(), Is}...};

0 commit comments

Comments
 (0)