std::transform (someContainer.begin (), someContainer.end (), std::back_inserter (otherContainer), [this] (const SomeUglyAndLongType& item) { return HandleItem (item); });
this
considered to be an implicit zero argument) fix one of them? On some pseudochaskele one could just write something like map (handleItem this) someContainer
(handleItem this)
. auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } // ... std::cout << curry (test) (1) (2) (3.0) ("four") << std::endl;
curry
functions should not be limited.curry (f)
return some object (let's call it CurryImpl
), which obviously needs the function f
that we passed to curry
, and also operator()
must be overloaded with it, and according to the condition of the problem it should take one The argument is not clear what type, and it is not clear what to return. Naturally, CurryImpl
template to be able to memorize any functions: template<typename F> class CurryImpl { const F m_f; // , curry public: CurryImpl (F f) : m_f { f } { } template<typename T> auto operator() (const T& arg) const { // - } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f }; }
arg
and either calls the desired function m_f
, if it is the last argument in the call chain, or returns another object that remembers this arg
.CurryImpl
. We do not know anything about these arguments, as well as about their types, so weβll have to add another argument to the template, and even with the variadic. You can directly store the values ββof the arguments, for example, in std::tuple
. You can tell our CurryImpl
about these arguments directly in the constructor. Total, the class declaration is modified something like this: template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } // };
m_f
? And just take and call, if possible - everything is fine!error
in the console and compiling too early . Actually, all these std::enable_if
and company are based exactly on SFINAE.m_f
only when such a call is well-formed. This will help us a great template function std::result_of
. std::result_of<F (T1, T2, ...)>
defines a nested type
, equal to the type returned by object F, if it is called with arguments of type T1, T2, ... It is described in more detail, for example, here . Actually, keywords by reference, for C ++ 14:ArgTypes ... in an unevaluated context.
std::result_of_t<...>
instead of typename std::result_of<...>::type
. template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg) const // PrevArgs β CurryImpl, { // - m_f }
m_f
, which is of type F
, can be called with all previous arguments and the current one, then everything is fine, the function βexistsβ, if it is impossible, the compiler does not consider it.invoke
, which also takes one argument, remembers it and recursively returns a new object with the parent-brackets operator and all the rest. Somehow, for example: template<typename T> auto invoke (const T& arg) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; }
CurryImpl
, which retains all previous arguments plus one new one. At the level of types, this is reflected in the record PrevArgs..., T
, if you want, adding T
to the variadic-type list, and at the level of values, we simply connect two tuples, the old m_prevArgs
and the new single-element tuple.invoke
overloads in it, possibly the first one that calls the function, otherwise you can never stop saving arguments. How to do it? There are a lot of options here, my favorite in such cases is to use the fact that any overload is better than overloading with an ellipsis (aka ellipsis, aka C-style variadics). That is, we add another parameter that we will not even use, for example, int
to the first function and ...
to the second, and we get something like this: template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { // - m_f } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; }
int
compiler likes a lot more than ...
arg
) are stored in a tuple? We need to somehow unpack that tuple and pass the results of the unpacking to a function as usual arguments. The problem is that at the call point we donβt know at the stage of writing the code how many arguments we have, so we canβt just pick up std::get
our hands. Well, it's nice, it's not good in 2014 to do work for the compiler. If we had some way to make a variadic of numbers from 0 to N-1, we could write something like this: // Is 0 ( m_prevArgs)-1 template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg /*, -, Is */) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
std::get (m_prevArgs)... std::get (m_prevArgs), std::get (m_prevArgs), Is
.
, , C++11, C++14 STL! , . , std::index_sequence_for
, ( PrevArgs...
), invoke
invokeIndexed
:
return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {});
invokeIndexed
std::index_sequence
, :
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return m_f (std::get<Is> (m_prevArgs)..., arg); }
! ! , , :
struct Foo { auto doFoo (int baz, int qux) { return (m_bar + baz) / qux; } }; // ... Foo someFoo; const auto fooRes = Curry (&Foo::doFoo) (&someFoo) (2) (4);
: m_f (arguments)
well-formed, m_f
β - .
, , , , . , m_f
, --. , :
template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } };
invokeIndexed
:
template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); }
, - SFINAE , Invoke
, Args...
β , . , , , :
template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } };
, , , , : c
, , , -- . :
struct Foo { int m_state = 42; auto doFoo (int bar) { m_state += bar; return m_state; } }; Foo foo; curry (&Foo::doFoo) (foo) (1); // foo.m_state 42 curry (&Foo::doFoo) (&foo) (1); // foo.m_state 43
, -, .
#include <tuple> #include <type_traits> #include <utility> #include <iostream> #include <string> template<typename F, typename... PrevArgs> class CurryImpl { const F m_f; const std::tuple<PrevArgs...> m_prevArgs; public: CurryImpl (F f, const std::tuple<PrevArgs...>& prev) : m_f { f } , m_prevArgs { prev } { } template<typename T> auto operator() (const T& arg) const { return invoke (arg, 0); } private: template<typename T> std::result_of_t<F (PrevArgs..., T)> invoke (const T& arg, int) const { return invokeIndexed (arg, std::index_sequence_for<PrevArgs...> {}); } template<typename IF> struct Invoke { template<typename... IArgs> auto operator() (IF fr, IArgs... args) { return fr (args...); } }; template<typename R, typename C, typename... Args> struct Invoke<R (C::*) (Args...)> { auto operator() (R (C::*ptr) (Args...), C c, Args... rest) { return (c.*ptr) (rest...); } auto operator() (R (C::*ptr) (Args...), C *c, Args... rest) { return (c->*ptr) (rest...); } }; template<typename T, std::size_t... Is> auto invokeIndexed (const T& arg, std::index_sequence<Is...>) const { return Invoke<F> {} (m_f, std::get<Is> (m_prevArgs)..., arg); } template<typename T> auto invoke (const T& arg, ...) const { return CurryImpl<F, PrevArgs..., T> { m_f, std::tuple_cat (m_prevArgs, std::tuple<T> { arg }) }; } }; template<typename F> auto curry (F f) { return CurryImpl<F> { f, {} }; } auto test (int t1, int t2, double t3, const std::string& str) { return t1 * t2 * t3 * str.size (); } struct Foo { int m_bar; auto doFoo (int baz, int qux) { auto result = (m_bar + baz) / qux; ++m_bar; return result; } }; int main () { const auto res = curry (test) (1) (2) (3.0) ("four"); std::cout << res << std::endl; Foo someFoo { 42 }; const auto fooRes = curry (&Foo::doFoo) (&someFoo) (2) (4); std::cout << fooRes << " " << someFoo.m_bar << std::endl; someFoo.m_bar = 42; auto lambda = [someFoo] (int bar, int baz) mutable { return someFoo.doFoo (bar, baz); }; const auto lambdaRes = curry (lambda) (4) (2); std::cout << lambdaRes << std::endl; }
.
:
CurryImpl
, std::function
?
std::function
type erasure, . , .
std::tuple
?
, , , .
C++14, C++11 ?
, . C++14 , :
auto
, decltype
; compile-time- ( std::index_sequence_for
, ).
, , , β decltype
.
, ?
.
?
: - , , . , , .
production-ready?
, C++14 - , .
Source: https://habr.com/ru/post/238879/
All Articles