Using a producer-consumer pattern I'd like to submit calls to the member functions of struct A i.e., func_1() and func_2() by passing the name of the function object (something like A::func_1), and a list of arguments taken by these functions in a queue-like buffer queue_in. I'd then like to collect these results (here a std::variant of all the possible return types (double and int)) in another buffer queue_out for later processing.
At the moment, I'm only able to hack my way by having q_in hold std::string and enumerating all the possibilities manually. Of course I'm also missing passing any possible arguments to func_1() and func_2().
#include <iostream>
#include "blockingconcurrentqueue.h" // https://github.com/cameron314/concurrentqueue
#include <variant>
using Result = std::variant<double, int>;
using queue_in = moodycamel::BlockingConcurrentQueue<std::string>;
using queue_out = moodycamel::BlockingConcurrentQueue<Result>;
struct A {
explicit A(queue_in &q_in, queue_out &q_out) {
std::thread t([&]() {
for (;;) {
std::string s;
if (q_in.wait_dequeue_timed(s, -1)) {
if (s == "1")
q_out.enqueue(this->func_1());
else if (s == "2")
q_out.enqueue(this->func_2());
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
});
t.join();
}
double func_1() const { // func_1 might have arguments!
std::cout << "func_1() called.\n";
return 13.0f;
}
int func_2() const { // func_2 might have arguments!
std::cout << "func_2() called.\n";
return 1;
}
};
void producer(queue_in &q_in, const size_t N) {
for (size_t i = 0; i != N; ++i) {
q_in.enqueue("1" /*..., arguments for func_1*/); // prefer to call the function-object instead
q_in.enqueue("2" /*..., arguments for func_2*/);
}
}
void result_consumer(queue_out &q_out) {
for (;;) {
Result r;
if (q_out.wait_dequeue_timed(r, -1)) {
std::visit([](auto &&arg) {
std::cout << "The result is: " << arg << std::endl;
}, r);
}
std::this_thread::sleep_for(std::chrono::seconds(0));
}
}
int main() {
const size_t N = 2;
queue_in q_in;
queue_out q_out;
std::thread producer_thread(producer, std::ref(q_in), N);
std::thread result_consumer_thread(result_consumer, std::ref(q_out));
A a(q_in, q_out);
producer_thread.join();
result_consumer_thread.join();
}
How can I do this instead via function objects? Second, how do I invoke any possible arguments for the member functions of A. And third, can I avoid the use of a std::variant like result type?