variable tutorial pointer plus namespace implement how classes c++ templates overloading c++14 currying

c++ - tutorial - ¿Cómo debo hacer la función de curry?



pointer to function c++ (4)

Aquí está el código con el que estuve jugando mientras aprendía varias plantillas.
Es un ejemplo de juguete para ATD para punteros de función, y ATD en std :: function.
He hecho un ejemplo en lambdas, pero no he encontrado la forma de extraer los monumentos, así que no hay ATD para lamnda (todavía)

#include <iostream> #include <tuple> #include <type_traits> #include <functional> #include <algorithm> //this is helper class for calling (variadic) func from std::tuple template <typename F,typename ...Args> struct TupleCallHelper { template<int ...> struct seq {}; template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {}; template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; }; template<int ...S> static inline auto callFunc(seq<S...>,std::tuple<Args...>& params, F f) -> decltype(f(std::get<S>(params) ...)) { return f(std::get<S>(params) ... ); } static inline auto delayed_dispatch(F& f, std::tuple<Args... >& args) -> decltype(callFunc(typename gens<sizeof...(Args)>::type(),args , f)) { return callFunc(typename gens<sizeof...(Args)>::type(),args , f); } }; template <int Depth,typename F,typename ... Args> struct CurriedImpl; //curried base class, when all args are consumed template <typename F,typename ... Args> struct CurriedImpl<0,F,Args...> { std::tuple<Args...> m_tuple; F m_func; CurriedImpl(const F& a_func):m_func(a_func) { } auto operator()() -> decltype(TupleCallHelper<F,Args...>::delayed_dispatch(m_func,m_tuple)) { return TupleCallHelper<F,Args...>::delayed_dispatch(m_func,m_tuple); } }; template <typename F,typename ... Args> struct CurriedImpl<-1,F,Args ... > ; //this is against weird gcc bug //curried before all args are consumed (stores arg in tuple) template <int Depth,typename F,typename ... Args> struct CurriedImpl : public CurriedImpl<Depth-1,F,Args...> { using parent_t = CurriedImpl<Depth-1,F,Args...>; CurriedImpl(const F& a_func): parent_t(a_func) { } template <typename First> auto operator()(const First& a_first) -> CurriedImpl<Depth-1,F,Args...> { std::get<sizeof...(Args)-Depth>(parent_t::m_tuple) = a_first; return *this; } template <typename First, typename... Rem> auto operator()(const First& a_first,Rem ... a_rem) -> CurriedImpl<Depth-1-sizeof...(Rem),F,Args...> { CurriedImpl<Depth-1,F,Args...> r = this->operator()(a_first); return r(a_rem...); } }; template <typename F, typename ... Args> struct Curried: public CurriedImpl<sizeof...(Args),F,Args...> { Curried(F a_f): CurriedImpl<sizeof...(Args),F,Args...>(a_f) { } }; template<typename A> int varcout( A a_a) { std::cout << a_a << "/n" ; return 0; } template<typename A,typename ... Var> int varcout( A a_a, Var ... a_var) { std::cout << a_a << "/n" ; return varcout(a_var ...); } template <typename F, typename ... Args> auto curried(F(*a_f)(Args...)) -> Curried<F(*)(Args...),Args...> { return Curried<F(*)(Args...),Args...>(a_f); } template <typename R, typename ... Args> auto curried(std::function<R(Args ... )> a_f) -> Curried<std::function<R(Args ... )>,Args...> { return Curried<std::function<R(Args ... )>,Args...>(a_f); } int main() { //function pointers auto f = varcout<int,float>; auto curried_funcp = curried(f); curried_funcp(1)(10)(); //atd for std::function std::function<int(int,float)> fun(f); auto curried_func = curried(fun); curried_func(2)(5)(); curried_func(2,5)();//works too //example with std::lambda using Curried auto lamb = [](int a , int b , std::string& s){ std::cout << a + b << s ; }; Curried<decltype(lamb),int,int,std::string> co(lamb); auto var1 = co(2); auto var2 = var1(1," is sum/n"); var2(); //prints -> "3 is sum" }

En C ++ 14, ¿cuál es una buena manera de curry de funciones u objetos de función?

En particular, tengo una función sobrecargada foo con un número aleatorio de sobrecargas: algunas sobrecargas se pueden encontrar a través de ADL, otras se pueden definir en una gran variedad de lugares.

Tengo un objeto de ayuda:

static struct { template<class...Args> auto operator()(Args&&...args)const -> decltype(foo(std::forward<Args>(args)...)) { return (foo(std::forward<Args>(args)...));} } call_foo;

Eso me permite pasar la sobrecarga establecida como un solo objeto.

Si quisiera curry foo , ¿cómo debería hacerlo?

Como curry y la aplicación de funciones parciales a menudo se usan indistintamente, por curry quiero decir que si foo(a,b,c,d) es una llamada válida, entonces curry(call_foo)(a)(b)(c)(d) debe ser una llamada válida.


Aquí está mi intento de usar una semántica ávida, es decir, regresar tan pronto como se acumulen suficientes argumentos para una llamada válida a la función original ( Demo en Coliru ):

namespace detail { template <unsigned I> struct priority_tag : priority_tag<I-1> {}; template <> struct priority_tag<0> {}; // High priority overload. // If f is callable with zero args, return f() template <typename F> auto curry(F&& f, priority_tag<1>) -> decltype(std::forward<F>(f)()) { return std::forward<F>(f)(); } // Low priority overload. // Return a partial application template <typename F> auto curry(F f, priority_tag<0>) { return [f](auto&& t) { return curry([f,t=std::forward<decltype(t)>(t)](auto&&...args) -> decltype(f(t, std::forward<decltype(args)>(args)...)) { return f(t, std::forward<decltype(args)>(args)...); }, priority_tag<1>{}); }; } } // namespace detail // Dispatch to the implementation overload set in namespace detail. template <typename F> auto curry(F&& f) { return detail::curry(std::forward<F>(f), detail::priority_tag<1>{}); }

y una implementación alternativa sin una semántica ávida que requiera un extra () para invocar la aplicación parcial que permita acceder, por ejemplo, a f(int) f(int, int) desde el mismo conjunto de sobrecarga:

template <typename F> class partial_application { F f_; public: template <typename T> explicit partial_application(T&& f) : f_(std::forward<T>(f)) {} auto operator()() { return f_(); } template <typename T> auto operator()(T&&); }; template <typename F> auto curry_explicit(F&& f) { return partial_application<F>{std::forward<F>(f)}; } template <typename F> template <typename T> auto partial_application<F>::operator()(T&& t) { return curry_explicit([f=f_,t=std::forward<T>(t)](auto&&...args) -> decltype(f_(t, std::forward<decltype(args)>(args)...)) { return f(t, std::forward<decltype(args)>(args)...); }); }


Aquí está mi mejor intento actual.

#include <iostream> #include <utility> #include <memory>

Asistente de utilidad SFINAE de la clase:

template<class T>struct voider{using type=void;}; template<class T>using void_t=typename voider<T>::type;

Una clase de rasgos que le dice si Sig es una invocación válida, es decir, si std::result_of<Sig>::type es un comportamiento definido. En algunas implementaciones de C ++, basta con comprobar std::result_of , pero el estándar no lo exige:

template<class Sig,class=void> struct is_invokable:std::false_type {}; template<class F, class... Ts> struct is_invokable< F(Ts...), void_t<decltype(std::declval<F>()(std::declval<Ts>()...))> >:std::true_type { using type=decltype(std::declval<F>()(std::declval<Ts>()...)); }; template<class Sig> using invoke_result=typename is_invokable<Sig>::type; template<class T> using type=T;

Curry helper es una especie de lambda manual. Captura una función y un argumento. No está escrito como un lambda, por lo que podemos habilitar el reenvío de valores correcto cuando se usa en un contexto de valores, lo cual es importante cuando se hace curry:

template<class F, class T> struct curry_helper { F f; T t; template<class...Args> invoke_result< type<F const&>(T const&, Args...) > operator()(Args&&...args)const& { return f(t, std::forward<Args>(args)...); } template<class...Args> invoke_result< type<F&>(T const&, Args...) > operator()(Args&&...args)& { return f(t, std::forward<Args>(args)...); } template<class...Args> invoke_result< type<F>(T const&, Args...) > operator()(Args&&...args)&& { return std::move(f)(std::move(t), std::forward<Args>(args)...); } };

La carne y las papas:

template<class F> struct curry_t { F f; template<class Arg> using next_curry=curry_t< curry_helper<F, std::decay_t<Arg> >; // the non-terminating cases. When the signature passed does not evaluate // we simply store the value in a curry_helper, and curry the result: template<class Arg,class=std::enable_if_t<!is_invokable<type<F const&>(Arg)>::value>> auto operator()(Arg&& arg)const& { return next_curry<Arg>{{ f, std::forward<Arg>(arg) }}; } template<class Arg,class=std::enable_if_t<!is_invokable<type<F&>(Arg)>::value>> auto operator()(Arg&& arg)& { return next_curry<Arg>{{ f, std::forward<Arg>(arg) }}; } template<class Arg,class=std::enable_if_t<!is_invokable<F(Arg)>::value>> auto operator()(Arg&& arg)&& { return next_curry<Arg>{{ std::move(f), std::forward<Arg>(arg) }}; } // These are helper functions that make curry(blah)(a,b,c) somewhat of a shortcut for curry(blah)(a)(b)(c) // *if* the latter is valid, *and* it isn''t just directly invoked. Not quite, because this can *jump over* // terminating cases... template<class Arg,class...Args,class=std::enable_if_t<!is_invokable<type<F const&>(Arg,Args...)>::value>> auto operator()(Arg&& arg,Args&&...args)const& { return next_curry<Arg>{{ f, std::forward<Arg>(arg) }}(std::forward<Args>(args)...); } template<class Arg,class...Args,class=std::enable_if_t<!is_invokable<type<F&>(Arg,Args...)>::value>> auto operator()(Arg&& arg,Args&&...args)& { return next_curry<Arg>{{ f, std::forward<Arg>(arg) }}(std::forward<Args>(args)...); } template<class Arg,class...Args,class=std::enable_if_t<!is_invokable<F(Arg,Args...)>::value>> auto operator()(Arg&& arg,Args&&...args)&& { return next_curry<Arg>{{ std::move(f), std::forward<Arg>(arg) }}(std::forward<Args>(args)...); } // The terminating cases. If we run into a case where the arguments would evaluate, this calls the underlying curried function: template<class... Args,class=std::enable_if_t<is_invokable<type<F const&>(Args...)>::value>> auto operator()(Args&&... args,...)const& { return f(std::forward<Args>(args)...); } template<class... Args,class=std::enable_if_t<is_invokable<type<F&>(Args...)>::value>> auto operator()(Args&&... args,...)& { return f(std::forward<Args>(args)...); } template<class... Args,class=std::enable_if_t<is_invokable<F(Args...)>::value>> auto operator()(Args&&... args,...)&& { return std::move(f)(std::forward<Args>(args)...); } }; template<class F> curry_t<typename std::decay<F>::type> curry( F&& f ) { return {std::forward<F>(f)}; }

La función final es humorísticamente corta.

Tenga en cuenta que no se realiza ningún tipo de borrado. También tenga en cuenta que la solución teórica hecha a mano puede tener muchos menos move , pero no creo que innecesariamente copie en ninguna parte.

Aquí hay un objeto de función de prueba:

static struct { double operator()(double x, int y, std::nullptr_t, std::nullptr_t)const{std::cout << "first/n"; return x*y;} char operator()(char c, int x)const{std::cout << "second/n"; return c+x;} void operator()(char const*s)const{std::cout << "hello " << s << "/n";} } foo;

Y un código de prueba para ver cómo funciona:

int main() { auto f = curry(foo); // testing the ability to "jump over" the second overload: std::cout << f(3.14,10,std::nullptr_t{})(std::nullptr_t{}) << "/n"; // Call the 3rd overload: f("world"); // call the 2nd overload: auto x = f(''a'',2); std::cout << x << "/n"; // again: x = f(''a'')(2); }

ejemplo vivo

El código resultante es más que un poco de lío. Muchos de los métodos tuvieron que repetirse 3 veces para manejar los casos & , const& y const& && manera óptima. Las cláusulas de SFINAE son largas y complejas. Terminé usando tanto arguciones variables como varargs, con las variables para asegurar una diferencia de firma no importante en el método (y creo que con una prioridad más baja, no importa, el SFINA garantiza que solo una sobrecarga sea válida, excepto this calificadores). ).

El resultado de curry(call_foo) es un objeto que se puede llamar un argumento a la vez, o muchos argumentos a la vez. Puede llamarlo con 3 argumentos, luego 1, luego 1, luego 2, y hace principalmente lo correcto. No hay evidencia expuesta que le diga cuántos argumentos desea, aparte de intentar darle argumentos y ver si la llamada es válida. Esto es necesario para manejar casos de sobrecarga.

Una peculiaridad del caso de múltiples argumentos es que no pasará parcialmente el paquete a un curry , y usará el resto como argumentos para devolver el valor. Podría cambiar eso relativamente fácilmente cambiando:

return curry_t< curry_helper<F, std::decay_t<Arg> >>{{ f, std::forward<Arg>(arg) }}(std::forward<Args>(args)...);

a

return (*this)(std::forward<Arg>(arg))(std::forward<Args>(args)...);

y los otros dos similares. Eso evitaría que la técnica de "saltar sobre" una sobrecarga que de otra manera sería válida. ¿Pensamientos? Significaría que curry(foo)(a,b,c) sería lógicamente idéntico a curry(foo)(a)(b)(c) que parece elegante.

Gracias a @Casey cuya respuesta inspiró mucho de esto.

Revisión más reciente. Hace que (a,b,c) comporte de manera muy similar a (a)(b)(c) menos que la llamada funcione directamente.

#include <type_traits> #include <utility> template<class...> struct voider { using type = void; }; template<class...Ts> using void_t = typename voider<Ts...>::type; template<class T> using decay_t = typename std::decay<T>::type; template<class Sig,class=void> struct is_invokable:std::false_type {}; template<class F, class... Ts> struct is_invokable< F(Ts...), void_t<decltype(std::declval<F>()(std::declval<Ts>()...))> >:std::true_type {}; #define RETURNS(...) decltype(__VA_ARGS__){return (__VA_ARGS__);} template<class D> class rvalue_invoke_support { D& self(){return *static_cast<D*>(this);} D const& self()const{return *static_cast<D const*>(this);} public: template<class...Args> auto operator()(Args&&...args)&-> RETURNS( invoke( this->self(), std::forward<Args>(args)... ) ) template<class...Args> auto operator()(Args&&...args)const&-> RETURNS( invoke( this->self(), std::forward<Args>(args)... ) ) template<class...Args> auto operator()(Args&&...args)&&-> RETURNS( invoke( std::move(this->self()), std::forward<Args>(args)... ) ) template<class...Args> auto operator()(Args&&...args)const&&-> RETURNS( invoke( std::move(this->self()), std::forward<Args>(args)... ) ) }; namespace curryDetails { // Curry helper is sort of a manual lambda. It captures a function and one argument // It isn''t written as a lambda so we can enable proper rvalue forwarding when it is // used in an rvalue context, which is important when currying: template<class F, class T> struct curry_helper: rvalue_invoke_support<curry_helper<F,T>> { F f; T t; template<class A, class B> curry_helper(A&& a, B&& b):f(std::forward<A>(a)), t(std::forward<B>(b)) {} template<class curry_helper, class...Args> friend auto invoke( curry_helper&& self, Args&&... args)-> RETURNS( std::forward<curry_helper>(self).f( std::forward<curry_helper>(self).t, std::forward<Args>(args)... ) ) }; } namespace curryNS { // the rvalue-ref qualified function type of a curry_t: template<class curry> using function_type = decltype(std::declval<curry>().f); template <class> struct curry_t; // the next curry type if we chain given a new arg A0: template<class curry, class A0> using next_curry = curry_t<::curryDetails::curry_helper<decay_t<function_type<curry>>, decay_t<A0>>>; // 3 invoke_ overloads // The first is one argument when invoking f with A0 does not work: template<class curry, class A0> auto invoke_(std::false_type, curry&& self, A0&&a0 )-> RETURNS(next_curry<curry, A0>{std::forward<curry>(self).f,std::forward<A0>(a0)}) // This is the 2+ argument overload where invoking with the arguments does not work // invoke a chain of the top one: template<class curry, class A0, class A1, class... Args> auto invoke_(std::false_type, curry&& self, A0&&a0, A1&& a1, Args&&... args )-> RETURNS(std::forward<curry>(self)(std::forward<A0>(a0))(std::forward<A1>(a1), std::forward<Args>(args)...)) // This is the any number of argument overload when it is a valid call to f: template<class curry, class...Args> auto invoke_(std::true_type, curry&& self, Args&&...args )-> RETURNS(std::forward<curry>(self).f(std::forward<Args>(args)...)) template<class F> struct curry_t : rvalue_invoke_support<curry_t<F>> { F f; template<class... U>curry_t(U&&...u):f(std::forward<U>(u)...){} template<class curry, class...Args> friend auto invoke( curry&& self, Args&&...args )-> RETURNS(invoke_(is_invokable<function_type<curry>(Args...)>{}, std::forward<curry>(self), std::forward<Args>(args)...)) }; } template<class F> curryNS::curry_t<decay_t<F>> curry( F&& f ) { return {std::forward<F>(f)}; } #include <iostream> static struct foo_t { double operator()(double x, int y, std::nullptr_t, std::nullptr_t)const{std::cout << "first/n"; return x*y;} char operator()(char c, int x)const{std::cout << "second/n"; return c+x;} void operator()(char const*s)const{std::cout << "hello " << s << "/n";} } foo; int main() { auto f = curry(foo); using C = decltype((f)); std::cout << is_invokable<curryNS::function_type<C>(const char(&)[5])>{} << "/n"; invoke( f, "world" ); // Call the 3rd overload: f("world"); // testing the ability to "jump over" the second overload: std::cout << f(3.14,10,nullptr,nullptr) << "/n"; // call the 2nd overload: auto x = f(''a'',2); std::cout << x << "/n"; // again: x = f(''a'')(2); std::cout << x << "/n"; std::cout << is_invokable<decltype(foo)(double, int)>{} << "/n"; std::cout << is_invokable<decltype(foo)(double)>{} << "/n"; std::cout << is_invokable<decltype(f)(double, int)>{} << "/n"; std::cout << is_invokable<decltype(f)(double)>{} << "/n"; std::cout << is_invokable<decltype(f(3.14))(int)>{} << "/n"; decltype(std::declval<decltype((foo))>()(std::declval<double>(), std::declval<int>())) y = {3}; (void)y; // std::cout << << "/n"; }

versión en vivo


Esto no es un problema trivial. Obtener la semántica de propiedad correcta es complicado. A modo de comparación, consideremos algunas lambdas y cómo expresan la propiedad:

[=]() {} // capture by value, can''t modify values of captures [=]() mutable {} // capture by value, can modify values of captures [&]() {} // capture by reference, can modify values of captures [a, &b, c = std::move(foo)]() {} // mixture of value and reference, move-only if foo is // can''t modify value of a or c, but can b

Mi implementación por defecto captura por valor, captura por referencia cuando se pasa std::reference_wrapper<> (el mismo comportamiento que std::make_tuple() con std::ref() ), y reenvía los argumentos de invocación tal como están (lvalues ​​permanecen como lvalues , los valores siguen siendo valores). No podría decidir una solución satisfactoria para mutable , por lo que todas las capturas de valor son efectivamente const .

La captura de un tipo de solo movimiento hace que el functor solo se mueva. Esto, a su vez, significa que c es un curry_t y d es un tipo de solo movimiento, y c(std::move(d)) no invoca el functor capturado, entonces vincula c(std::move(d)) a un lvalue significa que las llamadas subsiguientes tienen que contener argumentos suficientes para invocar el functor capturado, o el lvalue se debe convertir en un rvalue (posiblemente a través de std::move() ). Esto tuvo un cierto cuidado con los calificadores de referencia. Tenga en cuenta que *this es siempre un valor l, por lo que los ref-calificadores se aplicaron al operator() .

No hay forma de saber cuántos argumentos necesita el functor capturado, ya que puede haber cualquier cantidad de sobrecargas, así que ten cuidado. No static_assert s that sizeof...(Captures) < max(N_ARGS) .

En general, la implementación toma alrededor de 70 líneas de código. Como se discutió en los comentarios, seguí la convención de curry(foo)(a, b, c, d) y foo(a, b, c, d) son equivalentes (aproximadamente), permitiendo el acceso a cada sobrecarga.

#include <cstddef> #include <functional> #include <type_traits> #include <tuple> #include <utility> template<typename Functor> auto curry(Functor&& f); namespace curry_impl { /* helper: typing using type = T; is tedious */ template<typename T> struct identity { using type = T; }; /* helper: SFINAE magic :) */ template<typename...> struct void_t_impl : identity<void> {}; template<typename... Ts> using void_t = typename void_t_impl<Ts...>::type; /* helper: true iff F(Args...) is invokable */ template<typename Signature, typename = void> struct is_invokable : std::false_type {}; template<typename F, typename... Args> struct is_invokable<F(Args...), void_t<decltype(std::declval<F>()(std::declval<Args>()...))>> : std::true_type {}; /* helper: unwraps references wrapped by std::ref() */ template<typename T> struct unwrap_reference : identity<T> {}; template<typename T> struct unwrap_reference<std::reference_wrapper<T>> : identity<T&> {}; template<typename T> using unwrap_reference_t = typename unwrap_reference<T>::type; /* helper: same transformation as applied by std::make_tuple() * * decays to value type unless wrapped with std::ref() * * use: modeling value & reference captures * * e.g. c(a) vs c(std::ref(a)) */ template<typename T> struct decay_reference : unwrap_reference<std::decay_t<T>> {}; template<typename T> using decay_reference_t = typename decay_reference<T>::type; /* helper: true iff all template arguments are true */ template<bool...> struct all : std::true_type {}; template<bool... Booleans> struct all<false, Booleans...> : std::false_type {}; template<bool... Booleans> struct all<true, Booleans...> : all<Booleans...> {}; /* helper: std::move(u) iff T is not an lvalue * * use: save on copies when curry_t is an rvalue * * e.g. c(a)(b)(c) should only copy functor, a, b, etc. once */ template<bool = false> struct move_if_value_impl { template<typename U> auto&& operator()(U&& u) { return std::move(u); } }; template<> struct move_if_value_impl<true> { template<typename U> auto& operator()(U& u) { return u; } }; template<typename T, typename U> auto&& move_if_value(U&& u) { return move_if_value_impl<std::is_lvalue_reference<T>{}>{}(std::forward<U>(u)); } /* the curry wrapper/functor */ template<typename Functor, typename... Captures> struct curry_t { /* unfortunately, ref qualifiers don''t change *this (always lvalue), * * so qualifiers have to be on operator(), * * even though only invoke_impl(std::false_type, ...) needs qualifiers */ #define OPERATOR_PARENTHESES(X, Y) / template<typename... Args> / auto operator()(Args&&... args) X { / return invoke_impl_##Y(is_invokable<Functor(Captures..., Args...)>{}, std::index_sequence_for<Captures...>{}, std::forward<Args>(args)...); / } OPERATOR_PARENTHESES(&, lv) OPERATOR_PARENTHESES(&&, rv) #undef OPERATOR_PARENTHESES Functor functor; std::tuple<Captures...> captures; private: /* tag dispatch for when Functor(Captures..., Args...) is an invokable expression * * see above comment about duplicate code */ #define INVOKE_IMPL_TRUE(X) / template<typename... Args, std::size_t... Is> / auto invoke_impl_##X(std::true_type, std::index_sequence<Is...>, Args&&... args) { / return functor(std::get<Is>(captures)..., std::forward<Args>(args)...); / } INVOKE_IMPL_TRUE(lv) INVOKE_IMPL_TRUE(rv) #undef INVOKE_IMPL_TRUE /* tag dispatch for when Functor(Capture..., Args...) is NOT an invokable expression * * lvalue ref qualifier version copies all captured values/references */ template<typename... Args, std::size_t... Is> auto invoke_impl_lv(std::false_type, std::index_sequence<Is...>, Args&&... args) { static_assert(all<std::is_copy_constructible<Functor>{}, std::is_copy_constructible<Captures>{}...>{}, "all captures must be copyable or curry_t must an rvalue"); return curry_t<Functor, Captures..., decay_reference_t<Args>...>{ functor, std::tuple<Captures..., decay_reference_t<Args>...>{ std::get<Is>(captures)..., std::forward<Args>(args)... } }; } /* tag dispatch for when F(As..., Args...) is NOT an invokable expression * * rvalue ref qualifier version moves all captured values, copies all references */ template<typename... Args, std::size_t... Is> auto invoke_impl_rv(std::false_type, std::index_sequence<Is...>, Args&&... args) { return curry_t<Functor, Captures..., decay_reference_t<Args>...>{ move_if_value<Functor>(functor), std::tuple<Captures..., decay_reference_t<Args>...>{ move_if_value<Captures>(std::get<Is>(captures))..., std::forward<Args>(args)... } }; } }; } /* helper function for creating curried functors */ template<typename Functor> auto curry(Functor&& f) { return curry_impl::curry_t<curry_impl::decay_reference_t<Functor>>{std::forward<Functor>(f), {}}; }

Demostración en vivo en Coliru demostrando semántica calificadora de referencia.