145
|
1 // { dg-do compile { target c++17 } }
|
|
2
|
|
3 #include <utility>
|
|
4 #include <tuple>
|
|
5 #include <functional>
|
|
6
|
|
7 #define LIFT_FWD(x) std::forward<decltype(x)>(x)
|
|
8
|
|
9 template <typename T>
|
|
10 inline
|
|
11 constexpr
|
|
12 auto
|
|
13 equal(
|
|
14 T &&t)
|
|
15 {
|
|
16 return [t = std::forward<T>(t)](const auto& obj)
|
|
17 -> decltype(obj == t)
|
|
18 {
|
|
19 return obj == t;
|
|
20 };
|
|
21 }
|
|
22
|
|
23 template <typename F, typename T>
|
|
24 struct is_tuple_invocable;
|
|
25
|
|
26 template <typename F, typename ... Ts>
|
|
27 struct is_tuple_invocable<F, std::tuple<Ts...>>
|
|
28 {
|
|
29 using type = typename std::is_invocable<F, Ts...>::type;
|
|
30 };
|
|
31
|
|
32 template <typename F>
|
|
33 inline
|
|
34 constexpr
|
|
35 auto
|
|
36 compose(
|
|
37 F&& f
|
|
38 )
|
|
39 noexcept
|
|
40 -> F
|
|
41 {
|
|
42 return std::forward<F>(f);
|
|
43 }
|
|
44
|
|
45 namespace detail {
|
|
46 template <typename F, typename Tail, typename ... T>
|
|
47 inline
|
|
48 constexpr
|
|
49 auto
|
|
50 compose(
|
|
51 std::true_type,
|
|
52 F&& f,
|
|
53 Tail&& tail,
|
|
54 T&& ... objs)
|
|
55 noexcept(noexcept(f(tail(std::forward<T>(objs)...))))
|
|
56 -> decltype(f(tail(std::forward<T>(objs)...)))
|
|
57 {
|
|
58 return f(tail(std::forward<T>(objs)...));
|
|
59 }
|
|
60 }
|
|
61 template <typename F, typename ... Fs>
|
|
62 inline
|
|
63 constexpr
|
|
64 auto
|
|
65 compose(
|
|
66 F&& f,
|
|
67 Fs&&... fs)
|
|
68 {
|
|
69 return [f = std::forward<F>(f), tail = compose(std::forward<Fs>(fs)...)]
|
|
70 (auto&& ... objs)
|
|
71 -> decltype(detail::compose(typename std::is_invocable<decltype(compose(std::forward<Fs>(fs)...)), decltype(objs)...>::type{},
|
|
72 f,
|
|
73 compose(std::forward<Fs>(fs)...),
|
|
74 LIFT_FWD(objs)...))
|
|
75 {
|
|
76 using tail_type = decltype(compose(std::forward<Fs>(fs)...));
|
|
77
|
|
78 #ifndef NOT_VIA_TUPLE
|
|
79 using args_type = std::tuple<decltype(objs)...>;
|
|
80 constexpr auto unitail = typename is_tuple_invocable<tail_type, args_type>::type{};
|
|
81 #else
|
|
82 constexpr auto unitail = typename std::is_invocable<tail_type, decltype(objs)...>::type{};
|
|
83 #endif
|
|
84
|
|
85 return detail::compose(unitail, f, tail, LIFT_FWD(objs)...);
|
|
86 };
|
|
87 }
|
|
88
|
|
89 template <auto N>
|
|
90 constexpr auto eq = equal(N);
|
|
91
|
|
92 static_assert(compose(eq<3>,
|
|
93 std::plus<>{})(1,2),
|
|
94 "compose is constexpr");
|