1 // PR c++/69066
2 // { dg-do compile { target c++14 } }
3 
4 template <typename T> T&& declval();
5 
6 template<typename T, T v>
7 struct integral_constant
8 {
9   static constexpr T                value = v;
10   typedef T                         value_type;
11   typedef integral_constant<T, v>   type;
value_typeintegral_constant12   constexpr operator value_type() const { return value; }
13 };
14 
15 typedef integral_constant<bool, true>     true_type;
16 typedef integral_constant<bool, false>    false_type;
17 
18 template <typename...>
19 using void_t = void;
20 
21 template <typename, typename = void>
22 class is_zero_callable : public false_type
23 {
24 };
25 
26 template <typename T>
27 class is_zero_callable<T, void_t<decltype(declval<T>()())>>
28     : public true_type
29 {
30 };
31 
32 template <typename TF, bool TLastStep>
33 struct curry_impl
34 {
execcurry_impl35     static auto exec(TF f)
36     {
37         // Bind `x` to subsequent calls.
38         return [=](auto x)
39         {
40             auto bound_f = [=](auto... xs) -> decltype(f(x, xs...))
41             {
42                 return f(x, xs...);
43             };
44 
45             // Recursive step.
46             return curry_impl<decltype(bound_f),
47                 is_zero_callable<decltype(bound_f)>{}>::exec(bound_f);
48         };
49     }
50 };
51 
52 template <typename TF>
53 struct curry_impl<TF, true>
54 {
55     static auto exec(TF f)
56     {
57         return f();
58     }
59 };
60 
61 template <typename TF>
62 auto curry(TF f)
63 {
64     return curry_impl<TF, is_zero_callable<decltype(f)>{}>::exec(f);
65 }
66 
67 int main()
68 {
69     auto sum = [](int x, int y)
70     {
71         return x + y;
72     };
73 
74     (void)curry(sum)(1)(1);
75 }
76