Given the following function:
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>
{
using return_type = typename std::result_of<F(Args...)>::type;
auto task = std::make_shared< std::packaged_task<return_type()> >(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
std::future<return_type> res = task->get_future();
return res;
}
What's the right way to pass a member function to ThreadPool::enqueue as parameter, say the object is:
Foo foo
and the function is:
foo.do_something();
I have tried to use std::bind and std::mem_fn with or without "&" and all failed.
In addition to what #IgorTandetnik has mentioned in the comments, you can also use std::bind with std::mem_fn to pass a member function to your method:
struct Foo
{
void do_something() {}
void do_something_else(int x, int y, std::string str) {}
};
int main()
{
Foo foo;
ThreadPool pool;
auto func_sth = std::bind(std::mem_fn(&Foo::do_something), foo);
auto func_sth_else = std::bind(std::mem_fn(&Foo::do_something_else), foo, 10 , 11, "hi");
pool.enqueue(func_sth);
pool.enqueue(func_sth_else);
return 0;
}
Related
Due to the fact that std::functional uses heap memory when combining it with an std::bind I wanted to replace the std::bind with a lambda expression but I do not quite know how to do this. Is this even possible?
#include <iostream>
#include <functional>
#include <utility>
template<typename Signature>
class Callback;
template<typename R, typename... Args>
class Callback<R(Args...)> final
{
public:
Callback() noexcept : mFunc() {}
template<typename Obj, typename Method,
typename std::enable_if_t<std::is_invocable_r<R, Method, Obj, Args...>::value, int> = 0>
Callback(Obj& obj, Method method)
{
// That does not work
mFunc = [&obj](Args... args){ return obj.method(args); };
// mFunc = std::bind(method, obj, std::placeholders::_1, std::placeholders::_1); would work
}
R operator()(Args... args) const { return mFunc(args...); }
private:
std::function<R(Args...)> mFunc;
};
struct Foo
{
Foo() {}
void print(int a, int b)
{
std::cout << a << b << "\n";
}
};
int main()
{
Foo foo;
Callback<void(int, int)> cb(foo, &Foo::print);
cb(1,2);
}
Compiler throws the following error message:
main.cpp:19:46: error: expression contains unexpanded parameter pack 'args'
mFunc = [&obj](Args... args){ return obj.method(args); };
^ ~~~~
main.cpp:19:19: warning: lambda capture 'obj' is not used [-Wunused-lambda-capture]
mFunc = [&obj](Args... args){ return obj.method(args); };
If you really want to pass a member function pointer then you need to use syntax for calling the method via a member function pointer:
mFunc = [&,method](Args...x){ return (obj.*method)(x...);};
However, it would be simpler if you'd accept free callables and let the caller bind the object to a member function if necessary.
related post: How to combine std::bind(), variadic templates, and perfect forwarding?
Is there a way to bind a function with variadic tuples ? Here incorrect code indicating the intent:
// t is an instance of T
auto f = std::bind(&T::iterate,t,???);
// args is an instance of std::tuple<Args...> args;
std::apply(f,args);
(note: I am unsure "variadic tuple" to be the right terminology. Looking forward editing the post with your correction)
Since C++20 you can use std::bind_front:
template<class T>
void print (T val) {
std::cout << val << std::endl;
}
struct T {
template<class ... Args>
void iterate(Args... args) {
int temp[] = { (print(args),0)... };
}
};
// all happens here
template<class ... Args>
void foo(const tuple<Args...>& args) {
T t;
auto f = std::bind_front(&T::iterate<Args...>,&t);
std::apply(f,args);
}
// the call
int i = 1;
foo(std::make_tuple(i,i+1,"bind is cool"));
If you want to use old std::bind, you can provide your own placeholders to be generated from pack:
template<int N>
struct MyPlaceholder {};
namespace std {
template<int N>
struct is_placeholder<MyPlaceholder<N>> : public integral_constant<int, N> {};
}
template<class ... Args, size_t ... Indices>
void foo2helper(const tuple<Args...>& args, std::index_sequence<Indices...>) {
T t;
auto f = std::bind(&T::iterate<Args...>,&t, (MyPlaceholder<Indices+1>{})...);
std::apply(f,args);
}
template<class ... Args>
void foo2(const tuple<Args...>& args) {
foo2helper(args, std::make_index_sequence<sizeof...(Args)>{});
}
// the call
foo2(std::make_tuple(2.34,"only bind"));
Live demo
Don't use bind, use a lambda instead:
auto f = [&t](auto... args){ t.iterate(args...); };
std::apply(f, args);
If you want perfect forwarding, that would look like:
auto f = [&t](auto&&... args){ t.iterate(std::forward<decltype(args)>(args)...); };
std::apply(f, args);
I'm trying to create arguments out of a variadic template and forward it to a stored function. If the arguments are (typename... Args) I want to iterate each type and fetch an argument of that type from a storage container and then forward the arguments to a function.
I've tried different methods but always end up with that I cant store an untyped vector of arguments and I can't forward a vector as seperated arguments.
This is some pseudocode-ish of what I want to accomplish.
template <typename S, typename... Args>
void store_lambda() {
vec.push_back([this]() -> void {
ArgumentList arguments;
(get_arguments<Args>(arguments), ...);
my_function(arguments...);
});
}
template <typename T>
void get_arguments(ArgumentList& arguments) {
arguments.append(inner_storage.get<T>();)
}
void my_function(SomeStruct& s, const AnotherStruct& as) {
// do something with arguments
}
The type ArgumentList is not implemented (and probly is impossible to do) but this is the system I'm trying to create.
EDIT: More explaination
This is how my system looks atm:
struct WorkerWrapperBase {
public:
virtual ~WorkerWrapperBase() {}
}
template <typename... Args>
using exec_fn = std::function<void()>;
template <typename Job>
using job_ptr = std::unique_ptr<Job>;
template <typename J, typename R = void, typename... Args>
struct WorkerWrapper {
exec_fn<Args...> fn;
job_ptr<J> job_ptr;
WorkerWrapper(J* job, R (S::*f)(Args...) const)
: job_ptr{job_ptr<J>(job)} {
fn = [this, f]() -> R {
(job_ptr.get()->*f)(/* send arguments fetched from Args as explained above */);
};
}
};
struct CollectionOfWorkers {
std::vector<WorkerWrapperBase> workers;
template <typename Worker>
void add() {
workers.push_back(WorkerWrapper(new Worker(), &Worker::execute));
}
}
Usage would look like this:
struct TestWorker {
void execute(SomeStruct& s, const AnotherStruct& as) const {
// do something with arguments
}
}
CollectionOfWorkers.add<TestWorker>();
// and then somewhere we can loop each Worker and call their execute function
I want to create a clean API where you can create a Worker with a simple struct containing an execute function. The types of the parameters will then be used to try to get the reference of an instance of each type thats stored in a container. And then send it to the execute function. The idea was taken from this Game Engine talk
We can bind together a function and arguments to be called later very easily:
auto bind_args = [](auto&& func, auto&&... args) {
return [=]() mutable {
return func(args...);
};
};
And we can erase this type so it can be executed later easily too:
template<class Ret = void>
struct FuncInterface {
virtual ~VirtualFunc() = default;
virtual Ret operator()() = 0;
// Provided to allow concrete classes to copy themselves
virtual FuncInterface* clone() const = 0;
};
template<class Ret, class Func>
struct ConcreteFunc : public FuncInterface<Ret> {
Func func;
Ret operator()() override {
func();
}
FuncInterface* clone() const override {
return new ConcreteFunc<Ret, Func>{func};
}
};
Let's add a helper function to make concrete funcs using bind_args:
auto makeConcrete = [](auto&& func, auto&&... args) {
using Func = decltype(bind(func, args...));
using Ret = decltype(const_cast<Func&>(bind(func, args...))());
return ConcreteFunc<Ret, Func>{bind(func, args...)};
}
We can write a wrapper class that automatically handles ownership:
template<class Ret>
struct AnyFunc {
std::unique_ptr<FuncInterface> func;
AnyFunc() = default;
AnyFunc(AnyFunc const& f) : func(f.func->clone()) {}
AnyFunc(AnyFunc&& f) = default;
explicit AnyFunc(FuncInterface* func) : func(func) {}
Ret operator()() {
return (*func)();
};
};
And then we can write a WorkerContainer:
struct WorkerContainer {
std::vector<AnyFunc> funcs;
template<class Worker, class... Args>
void addWorker(Worker&& worker, Args&&... args) {
auto func = [=](auto&&... args) {
worker.execute(args...);
};
FuncInterface* ptr = new auto(makeConcrete(func, args...));
func.emplace_back(ptr);
}
};
If you have defaulted values for arguments, you can re-write this to provide them like so:
template<class... DefaultArgs>
struct WorkerContainer {
std::vector<AnyFunc> funcs;
std::tuple<DefaultArgs...> storage;
template<class Worker, class... Args>
void addWorker(Worker&& worker) {
auto func = [=, This=this]() {
worker.execute(std::get<Args>(This->storage)...);
};
FuncInterface* ptr = new auto(makeConcrete(func));
func.emplace_back(ptr);
}
};
I want to name a thread, but unfortunately the pthread_setname_np() on Mac works only inside current thread.
Then I do the wrapper around std::thread with a following constructor:
template <class F, class ... Args>
Thread::Thread(const char* name, F&& f, Args&&... args) {
thread_ = std::thread([name, f, args...]() {
pthread_setname_np(name);
f(args...);
});
}
But it doesn't work with class methods:
error: called object type '<complex type>' is not a function or function pointer
f(args...);
^
In the code like this:
threads_.emplace_back("Name", &Aggregator<T>::DoPop, this, some_arg);
What is a proper way to wrap the std::thread and set the thread name, preserving the whole interface excepting the name argument in the constructor?
You can use std::mem_fn to call a member function. The first argument in args has to be the pointer to the member object.
Example:
#include <thread>
#include <functional>
template <class F, class ... Args>
std::thread thread_factory(const char* name, F&& f, Args&&... args) {
return std::thread([=]{
pthread_setname_np(name);
auto fun = std::mem_fn(f);
fun(args...);
});
}
struct test {
int t(int val) {
return val;
}
};
int main() {
test t;
auto b = thread_factory("name", &test::t, &t, 5);
b.join();
}
you have to bind your member function to a class instance. here's your function presented slightly differently with a (working) test:
#include <iostream>
#include <thread>
template <class F, class ... Args>
std::thread launch_named_thread(const char* name, F&& f, Args&&... args) {
return std::thread([name, f, args...]() {
pthread_setname_np(name);
f(args...);
});
}
struct myclass
{
void thread_loop(int i)
{
std::cout << i << std::endl;
}
};
auto main() -> int
{
myclass x;
auto t = launch_named_thread("hello", std::bind(&myclass::thread_loop, &x, 6));
// this could be:
// auto t = launch_named_thread("hello", std::bind(&myclass::thread_loop, &x, std::placeholders::_1), 6);
// the difference is subtle. i'll leave it to you to work out why
t.join();
return 0;
}
how could one do this in c++ today without using two separate holders?
typedef std::function<void(int a, int b)> f1;
typedef std::function<void(int a)> f2;
std::vector<f1> m;
void add(f1 f)
{
m.push_back(f);
}
void add(f2 f)
{
// add one more (unused) parameter to f2 so we can add f2 to f1 vector holder?
}
can we somehow overload f1 function to include different set of parameters?
could this be solved by variadic templates nowdays or something similar?
Create a new lambda matching the new signature and add that instead:
void add(f2 f)
{
m.push_back( [g = std::move(f)](int a, int /* unused */){ g(a); } );
}
This wraps a std::function in a lambda that ignores any extra args:
template<class R, class...Args>
auto ignore_extra_args( std::function<R(Args...)> f ) {
return [f = std::move(f)](Args...args, auto&&...)->R{
return f(std::forward<Args>(args)...);
};
}
it gets trickier if we don't want that needless layer of type erasure.
You need to find the longest prefix of Args... which you can invoke a given object f with, then invoke f with it. This involves some tricky metaprogramming.
It is far easier if you ask the caller to pass in a signature:
template<class Sig>
struct ignore_extra_args_helper;
template<class R, class...Args>
struct ignore_extra_args_helper<R(Args...)> {
template<class F>
auto operator()( F&& f ) {
return [f = std::forward<F>(f)](Args...args, auto&&...)->R{
return f(std::forward<Args>(args)...);
};
}
};
template<class Sig, class F>
auto ignore_extra_args( F&& f ) {
return ignore_extra_args_helper<Sig>{}(std::forward<F>(f));
}
which saves on possible overhead.
template<class F, decltype(std::declval<F const&>()(1,1))* =nullptr>
void add(F&& f) {
m.push_back(std::forward<F>(f));
}
template<class F, class...Unused>
void add(F&& f, Unused&&...) {
add( ignore_extra_args<void(int)>(std::forward<F>(f)) );
}
live example