Reputation: 81
I have a class, which receives a lambda in constructor and is supposed to run the lambda on worker threads. I want to pass arguments for the runs to its queue, but of course to store them before execution, they need to be in a tuple.
I want to mostly be able to add arguments as variadics, both as const reference and move semantics, but if they need to be saved as tuples then there is no reason not to allow passing the ready tuples too... This is what I currently have:
#include <iostream>
using std::cout;
using std::endl;
#include <functional>
#include <queue>
#include <utility> // pair
#include <tuple>
#include <future>
template<class Ret, class... Args>
class Executor
{
public:
using ArgTpl = std::tuple<Args...>;
using Function = std::function<Ret(Args...)>;
typedef Ret(*FunctionPtr)(Args...);
private:
using Future = std::future<Ret>;
using Promise = std::promise<Ret>;
using Task = std::pair<Promise, ArgTpl>;
const Function callback;
std::queue<Task> task_queue;
public:
Executor(Function f) : callback(f) {}
Executor(FunctionPtr fp) : Executor(static_cast<Function>(fp)) {}
~Executor() {}
//
Future push(const Args&... args)// requires (sizeof...(args) != 0)
{
cout << "Args&..." << endl;
return push(std::forward_as_tuple(args...));
}
Future push(Args&&... args)// requires (sizeof...(args) != 0)
{
cout << "Args&&..." << endl;
return push(std::forward_as_tuple(args...));
}
Future push(const ArgTpl& args)
{
cout << "ArgTpl&" << endl;
ArgTpl a = args;
return push(std::move(a));
}
Future push(ArgTpl&& args)
{
cout << "ArgTpl&&" << endl;
Promise p;
Future f = p.get_future();
task_queue.emplace(std::make_pair(std::move(p), std::move(args)));
return f;
}
};
int func()
{
return 2;
}
int main()
{
//*/
{
std::function lbd = []() -> int { return 1; };
//Executor thrdmgr(lbd);
Executor thrdmgr(func);
//cout << "1st:" << endl;
//thrdmgr.push();
//cout << "2nd:" << endl;
//thrdmgr.push(); // ???
cout << "3rd:" << endl;
std::tuple<> t;
thrdmgr.push(t);
cout << "4th:" << endl;
thrdmgr.push(std::move(t));
}
/*/
{
std::function lbd = [](const std::string& str) -> void { cout << "Hello: " << str << endl; };
Executor thrdmgr(lbd);
//cout << "1st:" << endl;
//const std::string s1 = "strref";
//thrdmgr.push(s1);
//cout << "2nd:" << endl;
//std::string s2 = "strmove";
//thrdmgr.push(std::move(s2));
cout << "3rd:" << endl;
const std::tuple<std::string> t {"tuple"};
thrdmgr.push(t);
cout << "4th:" << endl;
thrdmgr.push(std::move(t));
}
//*/
system("pause");
}
It compiles and works, but I am not sure if I am using the proper move/forwarding/etc everywhere.
However I'm not even able to call all of the overloads, so maybe this whole endeavor is pointless... I thought that only for void
arg, the first two overloads will be the same and I tried adding the requires (sizeof...(args) != 0)
but it's the same even for the string
example.
The const Args&...
and Args&&...
are too similar and I'm getting member function already defined or declared
. That's why in the main
the 1st
and 2nd
are commented out.
How should it be done properly? Or maybe some of these overloads are unnecessary?
Upvotes: 0
Views: 86