Created
March 18, 2014 21:41
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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