Skip to content

Instantly share code, notes, and snippets.

@qsorix
Created March 18, 2014 21:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save qsorix/9630338 to your computer and use it in GitHub Desktop.
Save qsorix/9630338 to your computer and use it in GitHub Desktop.
Proof of concept. Callbacks that can be moved. This can be used to pass non-copyable resources between job queues of worker threads.
#include <memory>
#include <iostream>
#include <type_traits>
#include <tuple>
#include <vector>
/*
* seq<> and gen<> are used to call function with arguments saved as a tuple
*/
template<int...>
struct seq { };
template<int N, int... S>
struct gens : gens<N-1, N-1, S...>
{
};
template<int... S>
struct gens<0, S...>
{
typedef seq<S...> type;
};
/*
* callback that allows move
*/
template <typename Result, typename... Args>
struct movable_callback_base;
template <typename Result, typename... Args>
struct movable_callback_base<Result(Args...)>
{
virtual Result operator()(Args&&... p_args) = 0;
};
template <typename Func, typename TupleArgs, typename CallbackType>
struct movable_callback_impl;
template <typename Func, typename TupleArgs, typename Result, typename... Args>
struct movable_callback_impl<Func, TupleArgs, Result(Args...)> : public movable_callback_base<Result(Args...)>
{
Func m_f;
TupleArgs m_args;
template <typename... TArgs>
movable_callback_impl(Func f, TArgs&&... a)
: m_f(f), m_args(std::forward<TArgs>(a)...)
{
}
template <int... S>
auto do_call(seq<S...>, Args&&... p_args)
-> decltype(m_f(std::move(std::get<S>(m_args))..., std::forward<Args>(p_args)...))
{
return m_f(std::move(std::get<S>(m_args))..., std::forward<Args>(p_args)...);
}
Result operator()(Args&&... p_args)
{
return do_call(typename gens<std::tuple_size<TupleArgs>::value>::type(), std::forward<Args>(p_args)...);
}
};
template <typename CallbackType, typename Func, typename... Args>
movable_callback_impl<Func, std::tuple<Args...>, CallbackType>
make_movable_callback(Func f, Args&&... a)
{
return movable_callback_impl<Func, std::tuple<Args...>, CallbackType>(f, std::forward<Args>(a)...);
};
template <typename Callback>
struct movable_callback;
template <typename Result, typename... Args>
struct movable_callback<Result(Args...)>
{
std::unique_ptr<movable_callback_base<Result(Args...)>> m_cb;
template <typename MovableCallback>
movable_callback(MovableCallback&& p_cb)
: m_cb(new MovableCallback(std::forward<MovableCallback>(p_cb)))
{
}
Result operator()(Args&&... p_args)
{
return (*m_cb)(std::forward<Args>(p_args)...);
}
};
int sink(std::unique_ptr<int> p, int e)
{
if (p.get())
{
std::cout << "sink(" << *p << "), " << e << std::endl;
return *p + e;
}
else
{
std::cout << "sink no arg :(" << std::endl;
return 0;
}
};
int main()
{
std::unique_ptr<int> p1(new int(10));
std::unique_ptr<int> p2(new int(20));
std::vector<movable_callback<int(int)>> jobs;
jobs.emplace_back( make_movable_callback<int(int)>(sink, std::move(p1)) );
jobs.emplace_back( make_movable_callback<int(int)>(sink, std::move(p2)) );
for (auto& j : jobs)
{
auto r = j(3);
std::cout << "returned: " << r << std::endl;
}
for (auto& j : jobs)
{
auto r = j(3);
std::cout << "returned: " << r << std::endl;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment