-
Notifications
You must be signed in to change notification settings - Fork 73
/
Copy path187.md
200 lines (153 loc) · 7.46 KB
/
187.md
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
<details open><summary>Info</summary><p>
* **Did you know that C++17 made exception specifications be part of the type system?**
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html
</p></details><details open><summary>Example</summary><p>
```cpp
int main() {
void (*f1)();
void (*f2)() noexcept;
f1 = f2; // okay
f2 = f1; // ill-formed since C++17
}
```
> https://godbolt.org/z/Majq8f
</p></details><details open><summary>Puzzle</summary><p>
* **Can you implement `function_args_t` type trait which takes an invocable, respect `noexcept` and returns its arguments?**
```cpp
struct args{};
struct va_args {};
template<class T>
using function_args_t = /*TODO*/
int f1();
int f2() noexcept;
constexpr auto f3() noexcept -> void;
constexpr auto f4(...) noexcept -> void;
constexpr auto f5(int, ...) noexcept -> void;
constexpr auto f6(int...) noexcept -> void;
auto l1 = [] {};
auto l2 = [](int...) noexcept {};
auto l3 = [](auto...) noexcept {};
auto l4 = [](auto......) noexcept {};
constexpr auto l5 = [](auto..., auto......) constexpr noexcept {};
constexpr auto l6 = []<class... Ts>(Ts..., auto......) constexpr noexcept {};
constexpr auto l7 = []<auto...>(...) constexpr noexcept {};
struct f {
constexpr auto operator()(int, double, float) noexcept(false) -> void;
};
static_assert(std::is_same_v<std::tuple<>, function_args_t<decltype(&f1)>>);
static_assert(std::is_same_v<std::tuple<>, function_args_t<decltype(&f2)>>);
static_assert(std::is_same_v<std::tuple<>, function_args_t<decltype(&f3)>>);
static_assert(std::is_same_v<std::tuple<va_args>, function_args_t<decltype(&f4)>>);
static_assert(std::is_same_v<std::tuple<int, va_args>, function_args_t<decltype(&f5)>>);
static_assert(std::is_same_v<std::tuple<int, va_args>, function_args_t<decltype(&f6)>>);
static_assert(std::is_same_v<std::tuple<>, function_args_t<decltype(l1)>>);
static_assert(std::is_same_v<std::tuple<int, va_args>, function_args_t<decltype(l2)>>);
static_assert(std::is_same_v<std::tuple<args>, function_args_t<decltype(l3)>>);
static_assert(std::is_same_v<std::tuple<args, va_args>, function_args_t<decltype(l4)>>);
static_assert(std::is_same_v<std::tuple<args, va_args>, function_args_t<decltype(l5)>>);
static_assert(std::is_same_v<std::tuple<args, va_args>, function_args_t<decltype(l6)>>);
static_assert(std::is_same_v<std::tuple<va_args>, function_args_t<decltype(l7)>>);
static_assert(std::is_same_v<std::tuple<int, double, float>, function_args_t<f>>);
```
> https://godbolt.org/z/Gq1Pxe
</p></details><details><summary>Solutions</summary><p>
```cpp
// forward decl for later specialization
template <class T> struct function_args;
// specialization for regular function
template <class R, class... Ts, auto NE>
struct function_args<R(Ts...) noexcept(NE)> {
using arg_list_t = std::tuple<Ts...>;
};
// specialization for varargs function
template <class R, class... Ts, auto NE>
struct function_args<R(Ts..., ...) noexcept(NE)> {
using arg_list_t = std::tuple<Ts..., va_args>;
};
// combinatorial explosion ahead
// specializations for const and non-const member functions
// with and without varargs
template <class C, class R, class... Ts, auto NE>
struct function_args<R(C::*)(Ts...) const noexcept(NE)> : function_args<R(Ts...) noexcept(NE)> {};
template <class C, class R, class... Ts, auto NE>
struct function_args<R(C::*)(Ts..., ...) const noexcept(NE)> : function_args<R(Ts..., ...) noexcept(NE)> {};
template <class C, class R, class... Ts, auto NE>
struct function_args<R(C::*)(Ts...) noexcept(NE)> : function_args<R(Ts...) noexcept(NE)> {};
// technically not needed for test
//template <class C, class R, class... Ts, auto NE>
//struct function_args<R(C::*)(Ts..., ...) noexcept(NE)> : function_args<R(Ts..., ...) noexcept(NE)> {};
// function overloads for getting the right thing out
// raw function pointers
template <class T> requires std::is_pointer_v<T>
constexpr auto fn_args() -> function_args<std::remove_pointer_t<T>>;
// non-generic lambdas
template <class T> requires requires { &T::operator(); }
constexpr auto fn_args() -> function_args<decltype(&T::operator())>;
// generic lambdas with class template parms
template <typename T> requires requires { &T::template operator()<args>; }
constexpr auto fn_args() -> function_args<decltype(&T::template operator()<args>)>;
// generic lambdas with NTTPs
template <typename T> requires requires { &T::template operator()<1>; }
constexpr auto fn_args() -> function_args<decltype(&T::template operator()<1>)>;
// one alias to rule them all
template <class T>
using function_args_t = decltype(fn_args<T>())::arg_list_t;
```
> https://godbolt.org/z/s7h3Tn
```cpp
template<class T>
struct function_traits : function_traits<decltype(&T::operator())> {};
template<class T> requires requires { T::template operator()<args>; }
struct function_traits<T> : function_traits<decltype(&T::template operator()<args>)> {};
template<class T> requires requires { T::template operator()<0>; }
struct function_traits<T> : function_traits<decltype(&T::template operator()<0>)> {};
template<class R, class... TArgs, auto Noexcept>
struct function_traits<R(*)(TArgs...) noexcept(Noexcept)> { using args = std::tuple<TArgs...>; };
template<class R, class B, class... TArgs>
struct function_traits<R(B::*)(TArgs...)> { using args = std::tuple<TArgs...>; };
template<class R, class... TArgs, auto Noexcept>
struct function_traits<R(*)(TArgs......) noexcept(Noexcept)> { using args = std::tuple<TArgs..., va_args>; };
template<class R, class B, class... TArgs, auto Noexcept>
struct function_traits<R(B::*)(TArgs...) const noexcept(Noexcept)> { using args = std::tuple<TArgs...>; };
template<class R, class B, class... TArgs, auto Noexcept>
struct function_traits<R(B::*)(TArgs......) const noexcept(Noexcept)> { using args = std::tuple<TArgs..., va_args>; };
template<class T>
using function_args_t = typename function_traits<T>::args;
```
> https://godbolt.org/z/9zcMe5
```cpp
namespace detail {
constexpr int some_nttp = 0;
}
template<typename T> struct func_info_t;
template<typename Ret, typename... Args, auto no_except_val>
struct func_info_t<Ret(*)(Args...) noexcept(no_except_val)> {
using args_t = std::tuple<Args...>;
};
template<typename Ret, typename... Args, auto no_except_val>
struct func_info_t<Ret(*)(Args..., ...) noexcept(no_except_val)> {
using args_t = std::tuple<Args..., va_args>;
};
template<typename Class, typename Ret, typename... Args, auto no_except_val>
struct func_info_t<Ret(Class::*)(Args...) noexcept(no_except_val)> {
using args_t = std::tuple<Args...>;
};
template<typename Class, typename Ret, typename... Args, auto no_except_val>
struct func_info_t<Ret(Class::*)(Args...) const noexcept(no_except_val)> {
using args_t = std::tuple<Args...>;
};
template<typename Class, typename Ret, typename... Args, auto no_except_val>
struct func_info_t<Ret(Class::*)(Args..., ...) const noexcept(no_except_val)> {
using args_t = std::tuple<Args..., va_args>;
};
template<typename T> requires std::is_pointer_v<T>
constexpr auto function_pointer_maker() -> T;
template<typename T> requires requires { &T::operator(); }
constexpr auto function_pointer_maker() -> decltype(&T::operator());
template<typename T> requires requires { &T::template operator()<args>; }
constexpr auto function_pointer_maker() -> decltype(&T::template operator()<args>);
template<typename T> requires requires { &T::template operator()<detail::some_nttp>; }
constexpr auto function_pointer_maker() -> decltype(&T::template operator()<detail::some_nttp>);
```
> https://godbolt.org/z/d9YxP9
</p></details>