cannot bind variadic function and save to a std::function - c++

I successfully implemented my own thread_pool class where I can submit lambdas that can return any value but can only take zero arguments. I would like to improve it, such that it can work like std::async, where one can call it as follows: std::async(my_function, arg_1, arg_2, ..., arg_n). As I have it right now it looks as follows:
template<typename T>
auto enqueue_task(T&& task) -> std::future<decltype(task())>
{
auto wrapper = std::make_shared<std::packaged_task<decltype(task())()>>(std::forward<T>(task));
{
//some mutex
std::unique_lock<std::mutex> mutex(mutex_);
//The task is added to a queue of std::function<void()>
tasks_.emplace([=] {(*wrapper)(); });
}
has_work_.notify_one();
return wrapper->get_future();
}
My ideal solution would be such, that I can pass arguments to functinons in my thread_pool like such:
pool.enqueue_task(my_function, arg_1, arg_2, ..., arg_n)
where arg_1, ..., arg_n are the arguments of my_func
For this I sucessfully create a function which can take a variadic amount of arguments, but I have not managed to save this function int my std::function queue. I read on this link:
Passing a variadic function as argument how to achieve my goal by using std::bind. Yet I have not managed to achieve my goal. Here is how I understood it, what turned out not to work:
//some function with variadic arguments
template <typename... Args>
void test1(Args&&... args)
{
}
void test2(int a)
{
}
//main method
std::function<void()> a = std::bind(test2, 2) //works
std::function<void()> b = std::bind(test1<int>, 1) //does not work

std::bind will pass argument as lvalue. From cppreference:
the ordinary stored argument arg is passed to the invokable object as lvalue argument
When you specify test1<int>, the function becomes void test1(int&&), which cannot accept lvalue.

Related

c++ forward variadac function arguments to a class constructor

In C++, is there a way to define a function that takes N number of random arguments (number and parameter types could be anything) and in that function, instantiates a class who's constructor expects those arguments. In pseudo-code, something like:
class ClassType {
ClassType(int, string){}
};
void func(Args ...) {
ClassType A(Args);
}
And better yet, define a function pointer for "func"
Yes it is possible. Output of this
#include <iostream>
#include <utility>
struct ClassType {
ClassType(int a, std::string b){
std::cout << a << b;
}
};
template <typename...Args>
void func(Args&& ... args) {
ClassType A(std::forward<Args>(args)...);
}
int main() {
func(12,std::string("foo"));
}
is
12foo
However, it isnt quite clear why you want func to be variadic when ClassTypes constructor only accepts int,string. Calling func with any other combination will fail.
And better yet, define a function pointer for "func"
You cannot have a function pointer to a template (you also cannot have a function pointer to a whole set of overloads). Thats not how function pointers work. What you can do is taking a function pointer to one particular instantiation of func:
auto fptr = &func<int,std::string>;
If you need some function like object that you can pass around then you can use a generic lambda instead of a bare function pointer (since C++17 I believe):
auto flamb = [](auto&&...args){ func(std::forward<decltype(args)>(args)...); };
This works because the lambda is of some type (albeit unnamed and unspecified) and only its operator() is templated. Hence you can pass such lambda around and only when actually calling it the respective operator() is instantiated. Though, also with that you can only call it with the right parameters (int and std::string).

using the 'this' pointer inside a std::function prototype

to my understanding a member function is different to a normal function because there is an additional this pointer parameter.
So my idea is to make is make the following member template function to one of my classes:
template <class T>
void ApplyFunction(function<void(vector<int>&, T)> fun, T val);
and then I will use it inside one of my classes like:
Thing.ApplyFunction(myMethod, this);
and Thing will use the myMethod from my current class instance.
A lot of this code is guesswork so I would like some clarification as to if this would work. Also not sure which way round it is:
void ApplyFunction(function<void(vector<int>&, T)> fun, T val);
or
void ApplyFunction(T val, function<void(vector<int>&, T)> fun);
A code sample describing why I might want something like this:
void ClassA::callbackMethod(vector<int> &array)
{
//I can edit the array here
}
void ClassA::someMethod(void)
{
ClassB B;
B.ApplyFunction(callbackMethod, this);
//now whenever B wants to edit the array, it can by using callbackMethod
B.ComplicatedStuff(); // B uses the callbackMethod multiple times here
}
It looks to me like you are just planning to invoke a method, and you don't need to store the callable. If that is the case you should not use std::function but simply take a callable as a template parameter.
template <class T>
void ApplyFunction(T&& func) {
func(/*pass in your vector here*/);
}
With that you can you can then call it from A by passing in a lambda.
void ClassA::someMethod(void)
{
ClassB B;
B.ApplyFunction([&](std::vector<int>& vec){
// do stuff with vec here
// or call a member function
callbackMethod(vec);
vec.push_back(2);
});
}
This will be faster since passing by template parameter like this gives almost no additional cost from just a normal function call. If the function is inline it can be as cheap as just calling a member function.
std::function is a type-erased wrapper for any callable and comes with overhead, only use it if you need to store the callable for later use.
Edit
If you like to store the function, you don't need a template, you can simply take a std::function as parameter in ApplyFunction.
void ApplyFunction(std::function<void(std::vector<int>&)> func) {
//Store it, call it now or call it later.
m_func = func;
m_func(/*pass in your vector here*/);
}
Call it the same way, with a lambda.
Using a lambda like this is the preferred method when binding a member function to an instance. Instead of passing this separately it's better to wrap it in a lambda and get it for free so to speak.

C++11 std::forward a pointer

I have a Signal class in my application that provides classes with an option to expose events (same as in .NET).
The class works and all is well.
Yesterday I saw this SO question (and its answer) and was familiarized with std::forward.
I decided to try to use it in my code so I changed every std::function<void(Args...)> to std::function<void(Args&&...)> and in the raise function (the operator()) I used the same logic I saw in the above link so now the function takes Args&&...args and the callback uses std::forward<Args>(args)...
Here's a simplified version of my Signal class (with some changes to make it a good example):
template<typename... Args> class Signal
{
public:
int operator+=(const std::function<void(Args&&...)>& func) {
int token = getNewToken();
m_subscribers.emplace(token, func);
return token;
}
void operator()(Args&&... args) {
for (auto it : m_subscribers) {
it.second(std::forward<Args>(args)...);
}
}
private:
std::map<int, std::function<void(Args&&...)>> m_subscribers;
};
int main() {
int* six = new int(6);
int seven = 7;
Signal<int*> e1;
e1 += [](int* x) { std::cout << *x; };
Signal<int> e2;
e2 += [](int x) { std::cout << x; };
e1(&seven);
e2(6);
e1(six); //Error C2664 'void Signal<int *>::operator ()(int *&&)':
// cannot convert argument 1 from 'int *' to 'int *&&'
e1(std::move(six)); //This is a workaround
return 0;
}
The issue I'm seeing is with classes (or main in this example) that try to raise events with pointers and I'm not sure how to solve this.
My main goal is to have the Signal class a general API and if the developers chose to use Signal<int*> I don't want him\her to raise with std::move.
What am I doing wrong here?
T&& is only a universal reference if T is a non-cv-qualified function template parameter. In your call operator:
void operator()(Args&&... args) {
Args isn't a template parameter of the function, it's a template parameter of the class. So for Signal<int*>, this operator() takes an rvalue reference to int*. Since six is an lvalue, that fails.
What you want is to provide the correct reference qualifications to Signal. Like so:
template<typename... Args>
class Signal
{
using F = std::function<void(Args...)>; // NB: Just Args...
public:
int operator+=(F func) {
int token = getNewToken();
m_subscribers.emplace(token, std::move(func));
return token;
}
void operator()(Args... args) { // NB: just Args...
for (auto& it : m_subscribers) { // NB: auto&
it.second(args...);
}
}
private:
std::map<int, F> m_subscribers;
};
Note that forwarding Args... is questionable anyway. What if you had two subscribers? Once you forward the args once you can't really use them a second time.
The above will make Signal<int*> do what you expect. The operator() will just take an int*, which you can pass either an lvalue or an rvalue to.
Barry's answer is correct, but perhaps not as clearly explained as it could be.
&& is only given its special treatment as a forwarding (or "universal") reference when template parameter deduction occurs. But there is no deduction occurring here:
Signal<int*> e1; // `Args...` is explicitly `int*`
...
e1(six); // `Args...` *has already been specified*
When template classes are instantiated, they are essentially transformed into normal classes that just happen to be written by the compiler. See this answer for an example of what this might look like if written out in C++ code.
In C++14, there is no way to trigger template-parameter deduction of class templates without an auxiliary function (not a constructor):
template <typename Args...>
Signal<Args...> make_signal(Args&&...) { return Signal<Args...>; }
....But note that in your case, this makes no sense: you don't want to infer the types of your arguments when create the Signal, you want to specify them in advance.
(Note that in C++17, there will be support for template argument deduction of class templates. I assume this means that it will be possible to forward template-class arguments, though it's not immediately clear to me what the implications of doing such a thing would be.)
What you want to permit is for arguments to be forwarded at call time. This is actually reasonably simple:
template<typename... Args> class Signal
{
public:
// .... skipping some code...
template <typename... CallArgs>
void operator()(CallArgs&&... args) {
callback(std::forward<CallArgs>(args)...);
}
};
....But, again, in your case this doesn't quite make sense, as noted in Barry's answer. You don't want to forward arguments if you have multiple callbacks, to prevent moving and re-using them.
It's possible to work around this by checking the size of m_subscribers and only using the forwarding code if it's 1, and just passing the arguments as-is otherwise. However, this might lead to confusing behavior, since the way callbacks are invoked shouldn't generally depend on the state of your Signal object. So you could perhaps write a separate class, SingletonSignal, for callbacks that must be invoked with forwarded arguments (e.g. in case a callback wants to transfer ownership of an uncopyable object such as unique_ptr).

std::bind and std::function overlap or complementary?

I was looking at this exemple here, combining std::bind and std::function so as to create a command: really neat! The code for the command class goes like this:
class Command
{
private:
std::function<void ()> _f;
public:
command() {}
command(std::function<void ()> f) : _f(f) {}
template <typename T> void setFunction (T t) {_f = t ;}
void execute()
{
if(!_f.empty())
_f();
}
};
Assuming I have a class MyClass containing a member function:
class MyClass
{
public:
void myMemberFn() {}
}
Then the calling code looks like:
MyClass myClass;
command(std::bind(&MyClass::myMemberFn, myClass));
Though I must admit I do not really understand why std::function is needed in addition to std::bind. It seems to me that bind already encapsulates the function call, so why is function needed in Command? Couldn't Commandstore a std::bind rather than a std::function?
I have been looking at documentation for both std::bind and std::function and did not get it...
Anyone has an idea of why std::functionis needed?
PS: I am assuming std::bind ~= boost::bind and std::function ~= boost::function
You have to store the result of the std::bind expression somewhere. The return type of std::bind itself is unspecified by the standard, so you cannot create a named member variable of that type (you can use the C++11 auto to create such a local variable, though!)
Also, any function taking std::function can (due to std::function implicit conversions) accept all sorts of callable objects, not just std::bind results - you can pass it a regular function pointer, a lambda, a custom function object, whatever that can be invoked.
From the bind documnentation,
A function object of unspecified type T, for which std::is_bind_expression<T>::value == true,
and which can be stored in std::function.
So
std::function<void ()> _f;
is needed to store the return value of
command(std::bind(&MyClass::myMemberFn, myClass));
so that this can be actually invoked later.

how to declare the type of the result of std::make_tuple, without using auto

I want to implement a "Task" class, which can store a function pointer along with some arguments to pass to it. like std::bind(). and I have some question about how to store the arguments.
class BaseTask {
public:
virtual ~BaseTask() {}
virtual void run() = 0;
};
template<typename ... MTArg>
class Task : public BaseTask {
public:
typedef void (*RawFunction)(MTArg...);
Task(RawFunction rawFunction, MTArg&& ... args) : // Q1: MTArg&& ... args
rawFunction(rawFunction),
args(std::make_tuple(std::forward<MTArg>(args)...)) {} // Q2: std::make_tuple(std::forward<MTArg>(args)...)
virtual void run() {
callFunction(GenIndexSequence<sizeof...(MTArg)>()); // struct GenIndexSequence<count> : IndexSequence<0, ..., count-1>
}
private:
template<unsigned int... argIndexs>
inline void callFunction() {
rawFunction(std::forward<MTArg>(std::get<argIndexs>(args))...);
}
private:
RawFunction rawFunction;
std::tuple<MTArg...> args; // Q3: std::tuple<MTArg...>
};
Q1: is && after MTArg necessary
Q2: is this way correct to init args
Q3: is type of args correct, do I need:
std::tuple<special_decay_t<MTArg>...>
according to this: http://en.cppreference.com/w/cpp/utility/tuple/make_tuple
// end of questions
I want Task can be used in this way:
void fun(int i, const int& j) {}
BaseTask* createTask1() {
return new Task<int, const int&>(&fun, 1, 2); // "2" must not be disposed at the time of task.run(), so inside Task "2" should be store as "int", not "const int&"
}
BaseTask* createTask2(const int& i, const int& j) {
return new Task<int, const int&>(&fun, i, j); // "j" must not be disposed at the time of task.run(), so inside Task "j" should be store as "int", not "const int&"
}
void test(){
createTask1()->run();
createTask2(1, 2)->run();
}
task will only be run no more then once, that is zero or one times.
You aren't allowed to use std::tuple::special_decay_t even if it exists: it is an implementation detail. That code on cppreference exists for exposition only: it works "as if" that type exists. If your implementation uses that code, that is an implementation detail that different compilers will not have, and the next iteration of your compiler is free to change/make private/rename/etc.
As exposition, it explains what you need to write if you want to repeat the special decay process of std::make_tuple and a few other C++11 interfaces.
As a first step, I'll keep your overall design, and repair it a touch. Then I'll point out an alternative.
MTArg... are the parameters of the function:
template<typename ... MTArg>
struct Task {
typedef void (*RawFunction)(MTArg...);
Here we want to forward some set of arguments into a tuple, but the arguments need not match MTArg -- they just have to be convertible:
template<typename ... Args>
explicit Task(RawFunction rawFunction, Args&&... args)
rawFunction(rawFunction),
args(std::make_tuple(std::forward<Args>(args)...)) {}
which the above checks. Note I made it explicit, as if Args... is empty, we don't want this to be a converting constructor.
void run() {
callFunction(GenIndexSequence<sizeof...(MTArg)>());
}
private:
template<unsigned int... argIndexs>
inline void callFunction() {
rawFunction(std::forward<MTArg>(std::get<argIndexs>(args))...);
}
RawFunction rawFunction;
std::tuple<MTArg...> args;
};
and then we write a make_task function:
template<typename ... MTArg, typename... Args>
Task<MTArg...> make_task( void(*raw)(MTArg...), Args...&& args ) {
return { raw, std::forward<Args>(args)... };
}
which looks something like that. Note that we deduce MTArg... from the function pointer, and Args... from the arguments.
Just because our function takes foo by value, does not mean we should make copies of it, or store an rvalue reference to it, or what have you.
Now, the above disagrees with how std::function and std::thread work, which is where special_decay_t comes in.
Usually when you store arguments to a function, you want to store actual copies, not references to possibly local variables or temporary variables that may go away. And if your function takes arguments by lvalue non-const reference, you want to take extra care at the call site that you aren't binding it to stack variables.
That is where reference_wrapper comes in and the special_decay_t bit: deduced arguments are decayed into literals, which have conventional lifetimes. Types packaged into std::reference_wrapper are turned into references, which lets you pass references through the interface.
I'd be tempted to duplicate the C++11 pattern, but force creators of a Task to explicitly reference_wrapper all types that are supposed to be passed by reference into the raw function.
But I am unsure, and the code to do that gets a touch messy.
Q1: is && after MTArg necessary
Task(RawFunction rawFunction, MTArg&& ... args) : // Q1: MTArg&& ... args
No, it is not necessary, since it is a concrete function (constructor in this case). It would matter if it was a template function, then args would be of universal reference type.
For the same reason, you do not need to use std::foward.
Q3: is type of args correct, do I need:
std::tuple<special_decay_t<MTArg>...>
Yes, because types should not be rvalues, if you want to store them in a tupple.