Looking for a way to implement a universal generic memoization function which will take a function and return the memoized version of the same?
Looking for something like #memo (from Norving's site)decorator in python.
def memo(f):
table = {}
def fmemo(*args):
if args not in table:
table[args] = f(*args)
return table[args]
fmemo.memo = table
return fmemo
Going more general, is there a way to express generic and reusable decorators in C++, possibly using the new features of C++11?
A compact one returning a lambda:
template <typename R, typename... Args>
std::function<R (Args...)> memo(R (*fn)(Args...)) {
std::map<std::tuple<Args...>, R> table;
return [fn, table](Args... args) mutable -> R {
auto argt = std::make_tuple(args...);
auto memoized = table.find(argt);
if(memoized == table.end()) {
auto result = fn(args...);
table[argt] = result;
return result;
} else {
return memoized->second;
}
};
}
In C++14, one can use generalized return type deduction to avoid the extra indirection imposed by returning std::function.
Making this fully general, permitting passing arbitrary function objects without wrapping them in std::function first is left as an exercise for the reader.
The right way to do memoization in C++ is to mix the Y-combinator in.
Your base function needs a modification. Instead of calling itself directly, it takes a templateized reference to itself as its first argument (or, a std::function<Same_Signature> recursion as its first argument).
We start with a Y-combinator. Then we add in a cache on the operator() and rename it to memoizer, and give it a fixed signature (for the table).
The only thing left is to write a tuple_hash<template<class...>class Hash> that does a hash on a tuple.
The type of the function that can be memoized is (((Args...)->R), Args...) -> R, which makes the memoizer of type ( (((Args...) -> R), Args...) -> R ) -> ((Args...) -> R). Having a Y-combinator around to produce a 'traditional' recursive implementation can also be useful.
Note that if the function memoized modifies its args during a call, the memoizer will cache the results in the wrong spot.
struct wrap {};
template<class Sig, class F, template<class...>class Hash=std::hash>
struct memoizer;
template<class R, class...Args, class F, template<class...>class Hash>
struct memoizer<R(Args...), F, Hash> {
using base_type = F;
private:
F base;
mutable std::unordered_map< std::tuple<std::decay_t<Args>...>, R, tuple_hash<Hash> > cache;
public:
template<class... Ts>
R operator()(Ts&&... ts) const
{
auto args = std::make_tuple(ts...);
auto it = cache.find( args );
if (it != cache.end())
return it->second;
auto&& retval = base(*this, std::forward<Ts>(ts)...);
cache.emplace( std::move(args), retval );
return decltype(retval)(retval);
}
template<class... Ts>
R operator()(Ts&&... ts)
{
auto args = std::tie(ts...);
auto it = cache.find( args );
if (it != cache.end())
return it->second;
auto&& retval = base(*this, std::forward<Ts>(ts)...);
cache.emplace( std::move(args), retval );
return decltype(retval)(retval);
}
memoizer(memoizer const&)=default;
memoizer(memoizer&&)=default;
memoizer& operator=(memoizer const&)=default;
memoizer& operator=(memoizer&&)=default;
memoizer() = delete;
template<typename L>
memoizer( wrap, L&& f ):
base( std::forward<L>(f) )
{}
};
template<class Sig, class F>
memoizer<Sig, std::decay_t<F>> memoize( F&& f ) { return {wrap{}, std::forward<F>(f)}; }
live example with a hard-coded hash function based off this SO post.
auto fib = memoize<size_t(size_t)>(
[](auto&& fib, size_t i)->size_t{
if (i<=1) return 1;
return fib(i-1)+fib(i-2);
}
);
I struggled with the same problem. I created macro that also support (with small modification in recursive code) recursion. Here it is:
#include <map>
#include <tuple>
#define MEMOIZATOR(N, R, ...) \
R _ ## N (__VA_ARGS__); \
std::map<std::tuple<__VA_ARGS__>, R> _memo_ ## N; \
template <typename ... Args> \
R N (Args ... args) { \
auto& _memo = _memo_ ## N; \
auto result = _memo.find(std::make_tuple(args...)); \
if (result != _memo.end()) { \
return result->second; \
} \
else { \
auto result = _ ## N (args...); \
_memo[std::make_tuple(args...)] = result; \
return result; \
} \
}
The usage is really simple:
MEMOIZATOR(fibonacci, long int, int);
long int _fibonacci(int n) { // note the leading underscore
// this makes recursive function to go through wrapper
if (n == 1 or n == 2) {
return 1;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
fibonacci(40) // uses memoizator so it works in linear time
// (try it with and without memoizator)
See it in action: http://ideone.com/C3JEUT :)
Although #KerrekSB posted a link to another answer, I though I'd throw my answer in the ring as well (it's probably slightly less complicated than the linked answer, although in essence it's very similar):
#include <functional>
#include <map>
#include <tuple>
#include <utility>
/*! \brief A template functor class that can be utilized to memoize any
* given function taking any number of arguments.
*/
template <typename R, typename... Args>
struct memoize_wrapper
{
private:
std::map<std::tuple<Args...>, R> memo_;
std::function<R(Args...)> func_;
public:
/*! \brief Auto memoization constructor.
*
* \param func an the std::function to be memoized.
*/
memoize_wrapper(std::function<R(Args...)> func)
: func_(func)
{ }
/*! \brief Memoization functor implementation.
*
* \param a Argument values that match the argument types for the
* (previously) supplied function.
* \return A value of return type R equivalent to calling func(a...).
* If this function has been called with these parameters
* previously, this will take O(log n) time.
*/
R operator()(Args&&... a)
{
auto tup = std::make_tuple(std::forward<Args>(a)...);
auto it = memo_.find(tup);
if(it != memo_.end()) {
return it->second;
}
R val = func_(a...);
memo_.insert(std::make_pair(std::move(tup), val));
return val;
}
}; //end struct memoize_wrapper
Edit: Example usage:
Edit2: As pointed out, this doesn't work with recursive functions.
#include "utility/memoize_wrapper.hpp"
#include <memory>
#include <vector>
#include <algorithm>
#include <iostream>
long factorial(long i)
{
long result = 1;
long current = 2;
while(current <= i) {
result *= current;
++current;
}
return result;
}
int main()
{
std::vector<int> arg {10, 9, 8, 7, 6, 10, 9, 8, 7, 6};
std::transform(arg.begin(), arg.end(), arg.begin(), memoize_wrapper<long, long>(factorial));
for(long i : arg) {
std::cout << i << "\n";
}
}
Below is a (thread safe) C++17 function template that acts like std::invoke but memoizes the result:
/**
* #brief Drop-in replacement for std::invoke which memoizes the return
* result.
*
* #param[in] function The function whose result needs to be cached
* #param[in] args The function arguments
*
* #tparam Function The function type
* #tparam Args The argument types
*
* #return A value obtained either by evaluating the function, or by
* recalling it from a cache.
*
* #note The function provided must not be a type-erase function object
* like a raw function pointer or std::function, because this
* function depends on the uniqueness of the Function template
* parameter. If you were to call invoke_memoized(f, a) and
* invoke_memoized(g, b) in the same translation unit, where f and g
* were function pointers of the same type, and a and b were
* arguments of the same type, you'd end up using the same cache for
* both functions f and g. A reasonable attempt is made to detect
* these misuse cases via static_assert.
*/
template<typename Function, typename... Args>
auto invoke_memoized(Function function, Args... args)
{
using key_type = std::tuple<Args...>;
using value_type = std::invoke_result_t<Function, Args...>;
static_assert(! std::is_same_v<Function, std::function<value_type(Args...)>>,
"cannot memoize on std::function (use a lambda instead)");
static_assert(! std::is_same_v<Function, value_type(*)(Args...)>,
"cannot memoize on function pointer (use a lambda instead)");
static std::mutex mutex;
static std::map<key_type, value_type> cache;
auto key = std::tuple(args...);
auto lock = std::lock_guard<std::mutex>(mutex);
if (cache.count(key))
{
return cache[key];
}
return cache[key] = std::apply(function, key);
}
You can use it like this:
auto c = invoke_memoized(std::plus<>(), 1, 2.3);
A static cache is maintained for each combination of the function object and argument types. As noted std::function and raw function pointers are rejected, as type-erased functions would get their caches mixed up. You can easily modify this function to impose limits on the cache size.
Related
Suppose I have a variable constructors, which is a tuple of constructor functions represented in variadic generic lambdas.
// types for constructors
using type_tuple = std::tuple<ClassA, ClassB, ClassC>;
// Get a tuple of constructors(variadic generic lambda) of types in type_tuple
auto constructors = execute_all_t<type_tuple>(get_construct());
// For definitions of execute_all_t and get_construct, see link at the bottom.
I can instantiate an object with:
// Create an object using the constructors, where 0 is index of ClassA in the tuple.
ClassA a = std::get<0>(constructors)(/*arguments for any constructor of ClassA*/);
Is it possible to index the type in runtime with a magic_get like below?
auto obj = magic_get(constructors, 0)(/*arguments for any constructor of ClassA*/);
// Maybe obj can be a std::variant<ClassA, ClassB, ClassC>, which contains object of ClassA?
Edit: Ideally obj should be an instance of ClassA. If not possible, I can accept obj to be std::variant<ClassA, ClassB, ClassC>.
Please check out the minimal reproducible example: Try it online!
A similar question: C++11 way to index tuple at runtime without using switch
.
You might have your runtime get return std::variant, something like:
template <typename ... Ts, std::size_t ... Is>
std::variant<Ts...> get_impl(std::size_t index,
std::index_sequence<Is...>,
const std::tuple<Ts...>& t)
{
using getter_type = std::variant<Ts...> (*)(const std::tuple<Ts...>&);
getter_type funcs[] = {+[](const std::tuple<Ts...>& tuple)
-> std::variant<Ts...>
{ return std::get<Is>(tuple); } ...};
return funcs[index](t);
}
template <typename ... Ts>
std::variant<Ts...> get(std::size_t index, const std::tuple<Ts...>& t)
{
return get_impl(index, std::index_sequence_for<Ts...>(), t);
}
Then you might std::visit your variant to do what you want.
Demo
or for your "factory" example:
int argA1 = /*..*/;
std::string argA2 = /*..*/;
int argB1 = /*..*/;
// ...
auto obj = std::visit(overloaded{
[&](const A&) -> std::variant<A, B, C> { return A(argA1, argA2); },
[&](const B&) -> std::variant<A, B, C> { return B(argB1); },
[&](const C&) -> std::variant<A, B, C> { return C(); },
}, get(i, t))
This can probably be done more nicely, but here is an attempt according to your requirements in the comments.
Requires C++17, works on Clang, but gives an Internal Compiler Error on GCC.
It does require though, that you make the constructing function SFINAE-friendly, otherwise there is no way of checking whether it can be called:
So use
return [](auto... args) -> decltype(U(args)...) { return U(args...); };
instead of
return [](auto... args) { return U(args...); };
The behavior of this function given arguments tup and index is as follows:
It returns a lambda that when called with a list of arguments will return a std::variant of all the types that could result from calls of the form std::get<i>(tup)(/*arguments*/). Which one of these is actually called and stored in the returned variant is decided at runtime through the index argument. If index refers to a tuple element that cannot be called as if by std::get<index>(tup)(/*arguments*/), then an exception is thrown at runtime.
The intermediate lambda can be stored and called later. Note however that it saves a reference to the tup argument, so you need to make sure that the argument out-lives the lambda if you don't call and discard it immediately.
#include <tuple>
#include <type_traits>
#include <variant>
#include <utility>
#include <stdexcept>
template<auto V> struct constant_t {
static constexpr auto value = V;
using value_type = decltype(value);
constexpr operator value_type() const {
return V;
}
};
template<auto V>
inline constexpr auto constant = constant_t<V>{};
template<auto V1, auto V2>
constexpr auto operator+(constant_t<V1>, constant_t<V2>) {
return constant<V1+V2>;
}
template<typename T>
struct wrap_t {
using type = T;
constexpr auto operator+() const {
return static_cast<wrap_t*>(nullptr);
}
};
template<typename T>
inline constexpr auto wrap = wrap_t<T>{};
template<auto A>
using unwrap = typename std::remove_pointer_t<decltype(A)>::type;
template <typename Tup>
auto magic_get(Tup&& tup, std::size_t index) {
return [&tup, index](auto&&... args) {
// Get the input tuple size
constexpr auto size = std::tuple_size_v<std::remove_const_t<std::remove_reference_t<Tup>>>;
// Lambda: check if element i of tuple is invocable with given args
constexpr auto is_valid = [](auto i) {
return std::is_invocable_v<decltype(std::get<i>(tup)), decltype(args)...>;
};
// Lambda: get the wrapped return type of the invocable element i of tuple with given args
constexpr auto result_type = [](auto i) {
return wrap<std::invoke_result_t<decltype(std::get<i>(tup)), decltype(args)...>>;
};
// Recursive lambda call: get a tuple of wrapped return type using `result_type` lambda
constexpr auto valid_tuple = [=]() {
constexpr auto lambda = [=](auto&& self, auto i) {
if constexpr (i == size)
return std::make_tuple();
else if constexpr (is_valid(i))
return std::tuple_cat(std::make_tuple(result_type(i)), self(self, i + constant<1>));
else
return self(self, i + constant<1>);
};
return lambda(lambda, constant<std::size_t{0}>);
}();
// Lambda: get the underlying return types as wrapped variant
constexpr auto var_type =
std::apply([](auto... args) { return wrap<std::variant<unwrap<+args>...>>; }, valid_tuple);
/**
* Recursive lambda: get a variant of all underlying return type of matched functions, which
* contains the return value of calling function with given index and args.
*
* #param self The lambda itself
* #param tup A tuple of functions
* #param index The index to choose from matched (via args) functions
* #param i The running index to reach `index`
* #param j The in_place_index for constructing in variant
* #param args The variadic args for callling the function
* #return A variant of all underlying return types of matched functions
*/
constexpr auto lambda = [=](auto&& self, auto&& tup, std::size_t index, auto i, auto j,
auto&&... args) -> unwrap<+var_type> {
if constexpr (i == size)
throw std::invalid_argument("index too large");
else if (i == index) {
if constexpr (is_valid(i)) {
return unwrap<+var_type>{std::in_place_index<j>,
std::get<i>(tup)(decltype(args)(args)...)};
} else {
throw std::invalid_argument("invalid index");
}
} else {
return self(self, decltype(tup)(tup), index, i + constant<1>, j + constant<is_valid(i)>,
decltype(args)(args)...);
}
};
return lambda(lambda, std::forward<Tup>(tup), index, constant<std::size_t{0}>,
constant<std::size_t{0}>, decltype(args)(args)...);
};
}
In C++20, you can simplify this by
using std::remove_cvref_t<Tup> instead of std::remove_const_t<std::remove_reference_t<Tup>>
changing the definition of unwrap to:
template<auto A>
using unwrap = typename decltype(A)::type;
and using it as unwrap<...> instead of unwrap<+...>, which also allows removing the operator+ from wrap_t.
The purpose of wrap/unwrap:
wrap_t is meant to turn a type into a value that I can pass into functions and return from them without creating an object of the original type (which could cause all kinds of issues). It is really just an empty struct templated on the type and a type alias type which gives back the type.
I wrote wrap as a global inline variable, so that I can write wrap<int> instead of wrap<int>{}, since I consider the additional braces annoying.
unwrap<...> isn't really needed. typename decltype(...)::type does the same, it just gives back the type that an instance of wrap represents.
But again I wanted some easier way of writing it, but without C++20 this is not really possible in a nice way. In C++20 I can just pass the wrap object directly as template argument, but that doesn't work in C++17.
So in C++17 I "decay" the object to a pointer, which can be a non-type template argument, with an overloaded operator+, mimicking the syntax of the common lambda-to-function-pointer trick using the unary + operator (but I could have used any other unary operator).
The actual pointer value doesn't matter, I only need the type, but the template argument must be a constant expression, so I let it be a null pointer. The latter requirement is why I am not using the built-in address-of operator & instead of an overloaded +.
Here is a generic memoization wrapper I wrote for functions. It makes use of tuplehash.
template<typename R, typename... Args>
class memofunc{
typedef R (*func)(Args...);
func fun_;
unordered_map<tuple<Args...>, R, tuplehash::hash<tuple<Args...> > > map_;
public:
memofunc(func fu):fun_(fu){}
R operator()(Args&&... args){
auto key = make_tuple(std::forward<Args>(args)...);
auto q = map_.find(key);
if(q == map_.end()){
R res = fun_(std::forward<Args>(args)...);
map_.insert({key,res});
return res;
}else{
return q->second;
}
}
};
example of usage for Fibonacci numbers.
long long fibo(long long x){
static memofunc<long long, long long> memf(fibo);
// try to replace fibo with this new fibo but doesn't work, why?
// function<long long(long long)> fibo = memf;
if(x <= 2) return 1;
// this works but involves changing the original code.
// how to write code such that I dont need to manually add this code in?
return memf(x-1) + memf(x-2);
// old code
// return fibo(x-1) + fibo(x-2);
}
Question is, ideally I could just add a few line to the beginning of the recursive function and done with memoization. But simple replacement doesn't work, and this is where I stuck.
Your problem seems to be that you make a local copy of your memoizer at each function call, then destroy it.
Here is a simple one-argument version of your memoizer that seems to work:
#include <iostream>
#include <functional>
#include <unordered_map>
template<typename Sig, typename F=Sig* >
struct memoize_t;
template<typename R, typename Arg, typename F>
struct memoize_t<R(Arg), F> {
F f;
mutable std::unordered_map< Arg, R > results;
template<typename... Args>
R operator()( Args&&... args ) const {
Arg a{ std::forward<Args>(args)... }; // in tuple version, std::tuple<...> a
auto it = results.find(a);
if (it != results.end())
return it->second;
R retval = f(a); // in tuple version, use a tuple-to-arg invoker
results.emplace( std::forward<Arg>(a), retval ); // not sure what to do here in tuple version
return retval;
}
};
template<typename F>
memoize_t<F> memoize( F* func ) {
return {func};
}
int foo(int x) {
static auto mem = memoize(foo);
auto&& foo = mem;
std::cout << "processing...\n";
if (x <= 0) return foo(x+2)-foo(x+1); // bwahaha
if (x <= 2) return 1;
return foo(x-1) + foo(x-2);;
}
int main() {
std::cout << foo(10) << "\n";
}
live example
Note that foo(10) only does 10 invocations of foo.
This also admits:
#define CAT2(A,B,C) A##B##C
#define CAT(A,B,C) CAT2(A,B,C)
#define MEMOIZE(F) \
static auto CAT( memoize_static_, __LINE__, F ) = memoize(F); \
auto&& F = CAT( memoize_static_, __LINE__, F )
int foo(int x) {
MEMOIZE(foo);
std::cout << "processing...\n";
if (x <= 0) return 0;
if (x <= 2) return 1;
return foo(x-1) + foo(x-2);;
}
for people who like macros for this kind of thing.
A 3 step version might be better.
First, a prelude with a forward declaration of the function and memoizer wrapper.
Second, within the function, an alias for the function name, so recursive calls use the memorization function.
Third, after the declaration of the function, an alias for the function name, so external calls also use the memoized version.
The code above only memoizes recursive calls, never the initial call.
I need to pass a Lambda as callback (in particular for WinAPI). The idea is the following:
Store the lambda in a singleton class (every Lambda, also two identical ones, have different types) so it should be safe
LambdaSingleton<Lambda_Type>::instance = l;
Pass as callback the address of static method that invokes the lambda instance.
template <
typename Lambda,
typename Callback_Signature_R,
typename... Callback_Signature_Args>
struct LambdaCallbackSupport{
/**
* Callback method
*
* #param args
* The parameters to feed to the lambda
* #return
* The return value of the execution of the lambda
*/
static Callback_Signature_R __stdcall callback(Callback_Signature_Args... args){
return LambdaSingleton<Lambda>::instance(args);
}
};
I already have a working class for extracting informations about functions at compile time es:
template<
typename C,
typename R,
typename... Args>
struct Traits<R(__stdcall *)(Args...) const>{
//various typedefs for R, tuple of args, arity etc..
};
So i would get something like this:
//Example lambda
int toBeCaptured = 8;
auto lambda =
[&](std::string& str) -> size_t{
return toBeCaptured + str.length();
};
typedef decltype(lambda) Lambda;
//Expected callback signature
typedef size_t(__stdcall *CallbackSignature)(std::string&);
//Configure a callback support and pass its method
typedef Traits<CallbackSignature> callbackTraits;
typedef LambdaCallbackSupport<
Lambda,
callbackTraits::Result_Type,
callbackTraits::Args_Tuple_Pack> CallbackSupportType;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //How to unpack the tuple without actually have the arguments??
//Store the lambda instance statically
Singleton<Lambda>::instance = lambda;
//Pass the callback
void* pFunc = &CallbackSupportType::callback;
//Simulate invocation of callback
std::string str("may work?");
size_t ret = (*pFunc)(str);
Since i need only to let the compiler generate a callback class specialization (and not actually invoke its method) how can i apply the iterative unpacking technique proposed in other questions on this site?
Thank you
As a general answer to your question (how to do tuple unpacking), parameter packs can only be generated implicitly in the context of template argument type deduction, so if you want to "unpack" a type tuple<T1, ..., Tn> into a sequence of types T1, ..., Tn you have to instantiate that tuple and supply that instance in input to some function template:
template<typename... Ts>
void unpack(tuple<Ts...> const&) // Now you have an argument pack...
However, considering what you want to achieve (get a WinAPI callback from a lambda), I would not rely on tuples, and rather use a free function template. That can be done without introducing many levels of indirections and wrappers. Here is a possible simple solution:
#include <type_traits>
#include <memory>
template<typename F>
struct singleton
{
static void set_instance(F f) { instance.reset(new F(f)); }
static std::unique_ptr<F> instance;
};
template<typename F>
std::unique_ptr<F> singleton<F>::instance;
template<typename F, typename... Ts>
typename std::result_of<F(Ts...)>::type __stdcall lambda_caller(Ts... args)
{
if (singleton<F>::instance == nullptr)
{
// throw some exception...
}
else
{
return (*(singleton<F>::instance))(args...);
}
}
This is the framework. And this is how you would use it:
#include <iostream>
int main()
{
//Example lambda
int toBeCaptured = 8;
auto lambda =
[&](std::string& str) -> size_t{
return toBeCaptured + str.length();
};
singleton<decltype(lambda)>::set_instance(lambda);
size_t (__stdcall *pfn)(std::string&) = &lambda_caller<decltype(lambda)>;
std::string str = "hello";
int out = pfn(str);
std::cout << out;
return 0;
}
If you don't mind macros and want to simplify that further for some usage patterns (like the one above), you can add a macro like this:
#define get_api_callback(lambda) \
&lambda_caller<decltype(lambda)>; singleton<decltype(lambda)>::set_instance(lambda);
That would change your main() function into the following:
#include <iostream>
int main()
{
//Example lambda
int toBeCaptured = 8;
auto lambda =
[&](std::string& str) -> size_t{
return toBeCaptured + str.length();
};
// As simple as that...
size_t (__stdcall *pfn)(std::string&) = get_api_callback(lambda);
std::string str = "hello";
int out = pfn(str);
std::cout << out;
return 0;
}
EDIT: I use curry below, but have been informed this is instead partial application.
I've been trying to figure out how one would write a curry function in C++, and i actually figured it out!
#include <stdio.h>
#include <functional>
template< class Ret, class Arg1, class ...Args >
auto curry( Ret f(Arg1,Args...), Arg1 arg )
-> std::function< Ret(Args...) >
{
return [=]( Args ...args ) { return f( arg, args... ); };
}
And i wrote a version for lambdas, too.
template< class Ret, class Arg1, class ...Args >
auto curry( const std::function<Ret(Arg1,Args...)>& f, Arg1 arg )
-> std::function< Ret(Args...) >
{
return [=]( Args ...args ) { return f( arg, args... ); };
}
The tests:
int f( int x, int y )
{
return x + y;
}
int main()
{
auto f5 = curry( f, 5 );
auto g2 = curry( std::function<int(int,int)>([](int x, int y){ return x*y; }), 2 );
printf("%d\n",f5(3));
printf("%d\n",g2(3));
}
Yuck! The line initializing g2 is so large that i might as well have curried it manually.
auto g2 = [](int y){ return 2*y; };
Much shorter. But since the intent is to have a really generic and convenient curry function, could i either (1) write a better function or (2) somehow my lambda to implicitly construct an std::function? I fear the current version violates the rule of least surprise when f is not a free function. Especially annoying is how no make_function or similar-type function that i know of seems to exist. Really, my ideal solution would just be a call to std::bind, but i'm not sure how to use it with variadic templates.
PS: No boost, please, but i'll settle if nothing else.
EDIT: I already know about std::bind. I wouldn't be writing this function if std::bind did exactly what i wanted with the best syntax. This should be more of a special case where it only binds the first element.
As i said, my ideal solution should use bind, but if i wanted to use that, i'd use that.
Your curry function is just a scaled down inefficient subcase of std::bind (std::bind1st and bind2nd should not be used anymore now that we have std::result_of)
Your two lines read in fact
auto f5 = std::bind(f, 5, _1);
auto g2 = std::bind(std::multiplies<int>(), 2, _1);
after having used namespace std::placeholders. This carefully avoids the boxing into std::function and allows the compiler to inline more easily the result at the call site.
For functions of two arguments, hacking something like
auto bind1st(F&& f, T&& t)
-> decltype(std::bind(std::forward<F>(f), std::forward<T>(t), _1))
{
return std::bind(std::forward<F>(f), std::forward<T>(t), _1)
}
may work, but it is difficult to generalize to the variadic case (for which you'd end up rewriting a lot of the logic in std::bind).
Also currying is not partial application. Currying has "signature"
((a, b) -> c) -> (a -> b -> c)
ie. it is the action to transform a function taking two arguments into a function returning a function. It has an inverse uncurry performing the reverse operation (for mathematicians: curry and uncurry are isomorphisms, and define an adjunction). This inverse is very cumbersome to write in C++ (hint: use std::result_of).
This is a way to have currying in C++ and may or may not be relevant after the recent edits to the OP.
Due to overloading it is very problematic to inspect a functor and detect its arity. What is possible however is that given a functor f and an argument a, we can check if f(a) is a valid expression. If it isn't, we can store a and given a following argument b we can check if f(a, b) is a valid expression, and so on. To wit:
#include <utility>
#include <tuple>
/* Two SFINAE utilities */
template<typename>
struct void_ { using type = void; };
template<typename T>
using Void = typename void_<T>::type;
// std::result_of doesn't play well with SFINAE so we deliberately avoid it
// and roll our own
// For the sake of simplicity this result_of does not compute the same type
// as std::result_of (e.g. pointer to members)
template<typename Sig, typename Sfinae = void>
struct result_of {};
template<typename Functor, typename... Args>
struct result_of<
Functor(Args...)
, Void<decltype( std::declval<Functor>()(std::declval<Args>()...) )>
> {
using type = decltype( std::declval<Functor>()(std::declval<Args>()...) );
};
template<typename Functor, typename... Args>
using ResultOf = typename result_of<Sig>::type;
template<typename Functor, typename... Args>
class curry_type {
using tuple_type = std::tuple<Args...>;
public:
curry_type(Functor functor, tuple_type args)
: functor(std::forward<Functor>(functor))
, args(std::move(args))
{}
// Same policy as the wrappers from std::bind & others:
// the functor inherits the cv-qualifiers from the wrapper
// you might want to improve on that and inherit ref-qualifiers, too
template<typename Arg>
ResultOf<Functor&(Args..., Arg)>
operator()(Arg&& arg)
{
return invoke(functor, std::tuple_cat(std::move(args), std::forward_as_tuple(std::forward<Arg>(arg))));
}
// Implementation omitted for brevity -- same as above in any case
template<typename Arg>
ResultOf<Functor const&(Args..., Arg)>
operator()(Arg&& arg) const;
// Additional cv-qualified overloads omitted for brevity
// Fallback: keep calm and curry on
// the last ellipsis (...) means that this is a C-style vararg function
// this is a trick to make this overload (and others like it) least
// preferred when it comes to overload resolution
// the Rest pack is here to make for better diagnostics if a user erroenously
// attempts e.g. curry(f)(2, 3) instead of perhaps curry(f)(2)(3)
// note that it is possible to provide the same functionality without this hack
// (which I have no idea is actually permitted, all things considered)
// but requires further facilities (e.g. an is_callable trait)
template<typename Arg, typename... Rest>
curry_type<Functor, Args..., Arg>
operator()(Arg&& arg, Rest const&..., ...)
{
static_assert( sizeof...(Rest) == 0
, "Wrong usage: only pass up to one argument to a curried functor" );
return { std::forward<Functor>(functor), std::tuple_cat(std::move(args), std::forward_as_tuple(std::forward<Arg>(arg))) };
}
// Again, additional overloads omitted
// This is actually not part of the currying functionality
// but is here so that curry(f)() is equivalent of f() iff
// f has a nullary overload
template<typename F = Functor>
ResultOf<F&(Args...)>
operator()()
{
// This check if for sanity -- if I got it right no user can trigger it
// It *is* possible to emit a nice warning if a user attempts
// e.g. curry(f)(4)() but requires further overloads and SFINAE --
// left as an exercise to the reader
static_assert( sizeof...(Args) == 0, "How did you do that?" );
return invoke(functor, std::move(args));
}
// Additional cv-qualified overloads for the nullary case omitted for brevity
private:
Functor functor;
mutable tuple_type args;
template<typename F, typename Tuple, int... Indices>
ResultOf<F(typename std::tuple_element<Indices, Tuple>::type...)>
static invoke(F&& f, Tuple&& tuple, indices<Indices...>)
{
using std::get;
return std::forward<F>(f)(get<Indices>(std::forward<Tuple>(tuple))...);
}
template<typename F, typename Tuple>
static auto invoke(F&& f, Tuple&& tuple)
-> decltype( invoke(std::declval<F>(), std::declval<Tuple>(), indices_for<Tuple>()) )
{
return invoke(std::forward<F>(f), std::forward<Tuple>(tuple), indices_for<Tuple>());
}
};
template<typename Functor>
curry_type<Functor> curry(Functor&& functor)
{ return { std::forward<Functor>(functor), {} }; }
The above code compiles using a snapshot of GCC 4.8 (barring copy-and-paste errors), provided that there is an indices type and an indices_for utility. This question and its answer demonstrates the need and implementation of such things, where seq plays the role of indices and gens can be used to implement a (more convenient) indices_for.
Great care is taken in the above when it comes to value category and lifetime of (possible) temporaries. curry (and its accompanying type, which is an implementation detail) is designed to be as lightweight as possible while still making it very, very safe to use. In particular, usage such as:
foo a;
bar b;
auto f = [](foo a, bar b, baz c, int) { return quux(a, b, c); };
auto curried = curry(f);
auto pass = curried(a);
auto some = pass(b);
auto parameters = some(baz {});
auto result = parameters(0);
does not copy f, a or b; nor does it result in dangling references to temporaries. This all still holds true even if auto is substituted with auto&& (assuming quux is sane, but that's beyond the control of curry). It's still possible to come up with different policies in that regard (e.g. systematically decaying).
Note that parameters (but not the functor) are passed with the same value category in the final call as when they're passed to the curried wrapper. Hence in
auto functor = curry([](foo f, int) {});
auto curried = functor(foo {});
auto r0 = curried(0);
auto r1 = curried(1);
this means that a moved-from foo is passed to the underlying functor when computing r1.
With some C++14 features, partial application that works on lambda's can be implemented in a pretty concise way.
template<typename _function, typename _val>
auto partial( _function foo, _val v )
{
return
[foo, v](auto... rest)
{
return foo(v, rest...);
};
}
template< typename _function, typename _val1, typename... _valrest >
auto partial( _function foo, _val1 val, _valrest... valr )
{
return
[foo,val,valr...](auto... frest)
{
return partial(partial(foo, val), valr...)(frest...);
};
}
// partial application on lambda
int p1 = partial([](int i, int j){ return i-j; }, 6)(2);
int p2 = partial([](int i, int j){ return i-j; }, 6, 2)();
A lot of the examples people provided and that i saw elsewhere used helper classes to do whatever they did. I realized this becomes trivial to write when you do that!
#include <utility> // for declval
#include <array>
#include <cstdio>
using namespace std;
template< class F, class Arg >
struct PartialApplication
{
F f;
Arg arg;
constexpr PartialApplication( F&& f, Arg&& arg )
: f(forward<F>(f)), arg(forward<Arg>(arg))
{
}
/*
* The return type of F only gets deduced based on the number of arguments
* supplied. PartialApplication otherwise has no idea whether f takes 1 or 10 args.
*/
template< class ... Args >
constexpr auto operator() ( Args&& ...args )
-> decltype( f(arg,declval<Args>()...) )
{
return f( arg, forward<Args>(args)... );
}
};
template< class F, class A >
constexpr PartialApplication<F,A> partial( F&& f, A&& a )
{
return PartialApplication<F,A>( forward<F>(f), forward<A>(a) );
}
/* Recursively apply for multiple arguments. */
template< class F, class A, class B >
constexpr auto partial( F&& f, A&& a, B&& b )
-> decltype( partial(partial(declval<F>(),declval<A>()),
declval<B>()) )
{
return partial( partial(forward<F>(f),forward<A>(a)), forward<B>(b) );
}
/* Allow n-ary application. */
template< class F, class A, class B, class ...C >
constexpr auto partial( F&& f, A&& a, B&& b, C&& ...c )
-> decltype( partial(partial(declval<F>(),declval<A>()),
declval<B>(),declval<C>()...) )
{
return partial( partial(forward<F>(f),forward<A>(a)),
forward<B>(b), forward<C>(c)... );
}
int times(int x,int y) { return x*y; }
int main()
{
printf( "5 * 2 = %d\n", partial(times,5)(2) );
printf( "5 * 2 = %d\n", partial(times,5,2)() );
}
I know how to do memoization in Python easily but I need a faster way to compute them, so I am using C++. However, I have no clue how to memoize. I understand that it's about storing values into an array or vector and then scanning for its value when retrieving, but it'd be really helpful to see how this is done so I can try its speed.
Just for fun, here's a little generic memoizer I wrote some time ago. It requires variadic templates, naturally:
template <template <typename...> class Container, typename...> struct Memo;
template <typename R, typename... Args, template <typename...> class Container>
struct Memo<Container, R, std::tuple<Args...>>
{
Memo(std::function<R(Args...)> f) : func(f) { }
R operator()(Args && ...args)
{
const auto arg = std::make_tuple(args...);
typename CacheContainer::const_iterator it = cache.find(arg);
if (it == cache.cend())
{
it = cache.insert(typename CacheContainer::value_type(arg, func(std::forward<Args>(args)...))).first;
std::cout << "New call, memoizing..." << std::endl;
}
else
{
std::cout << "Found it in the cache!" << std::endl;
}
return it->second;
}
private:
typedef Container<typename std::tuple<Args...>, R> CacheContainer;
std::function<R(Args...)> func;
CacheContainer cache;
};
template <typename R, typename... Args>
Memo<std::map, R, std::tuple<Args...>> OMapMemoize(R(&f)(Args...))
{
return Memo<std::map, R, std::tuple<Args...>>(f);
}
template <typename R, typename... Args>
Memo<std::unordered_map, R, std::tuple<Args...>> UMapMemoize(R(&f)(Args...))
{
return Memo<std::unordered_map, R, std::tuple<Args...>>(f);
}
I'm not entirely sure if I got the rvalue-forwardiness right, as it's a long time ago that I wrote this. Anyway, here's a test case:
int foo(double, char) { return 5; }
int main()
{
auto f = OMapMemoize(foo);
auto g = UMapMemoize(foo);
int a, b;
a = f(1.0, 'a');
a = f(1.0, 'a');
a = f(1.0, 'a');
a = f(1.0, 'a');
b = g(1.0, 'a');
b = g(1.0, 'a');
b = g(1.0, 'a');
b = g(1.0, 'a');
return a;
}
Well the neatest way I can think of to do this in C++ is probably using a function object to store the memoized values. I guess this is probably slightly similar to your python decorator, although I have never really done any python. The code would look something like this:
template <typename T, T (*calc)(T)>
class mem {
std::map<T,T> mem_map;
public:
T operator()(T input) {
typename std::map<T,T>::iterator it;
it = mem_map.find(input);
if (it != mem_map.end()) {
return it->second;
} else {
T output = calc(input);
mem_map[input] = output;
return output;
}
}
};
The code defines a template class that takes in a typename and a function pointer, the function operator is then defined on the class allowing it to be called. The function operator takes in an input value checks if said value is in a map, then either simply returns it from the map or calculates it (using the function pointer), adds it to the map and then returns it.
So assuming you define some processing function like say:
int unity(int in) { return in; }
You would use the code like this:
mem<int, unity> mem_unity;
int y;
y = mem_unity(10);
So we define an instance of the mem class which takes our value type and processing function as template parameters, then simply call this class as a function.
No one except a student learning recursion would calculate factorials that way.
Memoization is a very good idea, especially if you're going to call the method repeatedly. Why throw away good work?
Another consideration is a better way to calculate factorials: use the natural log of the gamma function. It'll hold out against overflow longer, because you return a double value. The natural log will grow more slowly than the value. If you're calculating combinations, the natural log changes multiplication and division into addition and subtraction.
But, by all means, memoize for any implementation you use. If you're writing it in C++, I'd recommend using a std:map with the argument x as the key and the ln(gamma(x)) as the value.
Sorry, it's been too long since I've written C++ and STL. I'd rather use a hash map with O(1) read access time to having to iterate over the keys in O(n).
I like relying on lambda capture as in (uses std=c++14)
template<typename R, typename... Args>
auto memoize(std::function<R(Args...)>&& f)
{
using F = std::function<R(Args...)>;
std::map<std::tuple<Args...>,R> cache;
return ([cache = std::map<std::tuple<Args...>,R>{},
f = std::forward<F>(f)](Args&&... args) mutable
{
std::tuple<Args...> t(args...);
if (cache.find(t) == cache.end())
{
R r = f(std::forward<Args...>(args)...);
cache[t] = r;
}
return cache[t];
});
}