I'm trying to mimic std::thread constructor functionality:
template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );
I've tried stepping with debugger to see how it works but I couldn't figure it out.
How can I create and store bind type like thread's constructor does ?
Something like this (the syntax maybe wrong):
class myClass{
private:
auto bindType;
public:
template< class Function, class... Args >
explicit myClass( Function&& f, Args&&... args ) : bindType(somehowBind(f, args) {}
void evaluate() {bindType();}
};
Example of usage:
int test(int i) {return i;}
int main(){
myClass my(test, 5);
my.evaluate();
}
Note that I don't care if somehowBind function will ignore the return type i.e. its return type can be something like std::function.
All I wan't to do is understand how I can bind class... Args to a given function f such that after calling somehowBind it will act like std::bind does.
To clarify my point you can think about what I'm trying to achieve as follow:
thread t(test, 5); // unlike the usual std:::thread, this one is created in suspended mode therefore I need somehow to bind `f` with `5` and store it
t.start(); // now t is executed
It's kinda reminds C# and Java threads, they not executed right after construction.
For starters, to bind some parameters to a function using std::bind you simpy do:
// Some function.
void printValues(int x, double y) {
std::cout << x << " " << y << std::endl;
}
auto func = std::bind(printValues, 5, 2.0); // Bind params and return functor.
func(); // Evaluate function call (returns void in this case).
Next, to store a functor and its parameters in a class and you don't care about the return value when evaluating then simply use a lambda expression to wrap the std::bind expression (the lambda is used to drop the return value):
struct Foo {
template <typename Function, typename... Args>
Foo(Function&& func, Args&&... args) {
auto f = std::bind(std::forward<Function>(func), std::forward<Args>(args)...);
func_ = [f] { f(); };
// func_ = [f{std::move(f)}] { f(); }; // In C++14 you can move capture.
}
void evaluate() { func_(); }
std::function<void()> func_;
};
Also see this live example
If you're looking to store a variadic pack then see this answer: How to store variadic template arguments?
Related
I've defined a template function that receives std::function. and I want to send a member function. that works fine (example: test2)
How can I rewrite it so std::function receives any number of argument? (test3)
another question - can this be done without the std::bind?
struct Cls
{
int foo() { return 11; }
};
template<typename T>
void test2(std::function<T()> func)
{}
template<typename T, typename... Args>
void test3(std::function<T(Args... args)> func, Args&&... args)
{}
int main()
{
Cls ccc;
test2<int>(std::bind(&Cls::foo, ccc)); // Ok
test3<int>(std::bind(&Cls::foo, ccc)); // does not compile!
}
This is the error I receive:
no matching function for call to ‘test3<int>(std::_Bind_helper<false, int (Cls::*)(), Cls&>::type)’ 34 | test3<int>(std::bind(&Cls::foo, ccc));
The issue is that std::bind doesn't return a std::function, it returns some unspecified callable type. Therefore the compiler can't deduce the correct template parameters for test3.
The way to work around that is to make your function accept any callable type instead of trying to accept a std::function:
template <typename Func, typename... Args>
void test3(Func&& func, Args&&... args)
{}
This will work with a std::bind result, a lambda, a raw function pointer, a std::function, etc.
can this be done without the std::bind?
Sort of. A pointer to a member function always requires an instance of the class to be called on. You can avoid needing to explicitly std::bind the instance into a wrapper by passing it as a parameter and using the std::invoke helper to call the function. For pointers to member functions, std::invoke treats the first parameter as the object to call the member on.
For example:
struct Cls
{
int foo() { return 11; }
};
template <typename Func, typename... Args>
void test3(Func&& func, Args&&... args)
{
std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
}
void bar(double, int) {}
int main()
{
Cls ccc;
test3(bar, 3.14, 42); // Works with a raw function pointer
test3(&Cls::foo, ccc); // Works with a pointer to member function
test3([](int){}, 42); // Works with other callable types, like a lambda
}
Demo
can this be done without the std::bind?
Yes this can be done without std::bind as shown below.
struct Cls
{
int foo() { return 11; }
int func(int, double)
{
return 4;
}
};
template<typename className, typename... Param,typename Ret, typename... Args>
void test4(Ret (className::*ptrFunc)(Param... param),className& Object, Args... args)
{
(Object.*ptrFunc)(args...);
//std::invoke(ptrFunc, Object, args...); //WITH C++17
}
int main()
{
Cls ccc;
test4(&Cls::foo, ccc); //works
test4(&Cls::func, ccc, 4,5); //works
}
Working demo
With C++17 we can use std::invoke to replace the call (Object.*ptrFunc)(args...); with:
std::invoke(ptrFunc, Object, args...); //WITH C++17
C++17 std::invoke demo
Thing simple enough, I want to forward the call of a member function, along with its arguments, as described in the following snippet.
Please note that this is not a duplicate of this question, nor this one.
#include <iostream>
#include <functional>
template<class Function, class ... Args>
auto forward_args(Function&& f, Args&& ... args)
{
return f(std::forward<Args>(args)...);
}
int f(int i) { return i; }
struct A {
int get(int i) const { return i; }
};
int main()
{
std::cout << forward_args(f, 2) << std::endl; //ok
A a;
//std::cout << forward_args(&A::get, a, 2) << std::endl; //ko
static auto wrong_wrapper = &A::get;
//std::cout << forward_args(wrong_wrapper, a, 2) << std::endl; //ko again
static std::function<int (const A&, int)> wrapper = &A::get;
std::cout << forward_args(wrapper, a, 2) << std::endl;
}
The commented lines in the main function don't compile (g++ 10.2.0 -- error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘f (...)’, e.g. ‘(... ->* f) (...)’)
I don't quite understand what the compiler is trying to tell me, considering the last cll with the std::function wrapper does work. And, beside fixing the code, I'd also like to know why it doesn't work.
Calling a member function through pointer-to-member still requires this pointer, as in usual (direct) invocations. Simply put, you could succeeded calling A::get() like
static auto wrong_wrapper = &A::get;
(a.*wrong_wrapper)(2);
but what you got after forward_args was instantiated is
A::get(a, 2);
which is not the correct syntax in its nature.
Solution
As it has been already said in the comments section, if you are allowed to use C++17, employ std::invoke. If you aren't, you can work it around using std::reference_wrapper, which accepts any callable type.
template<class Function, class ... Args>
auto forward_args(Function f, Args&& ... args)
{
return std::ref(f)(std::forward<Args>(args)...);
}
I don't forward f here because std::reference_wrapper requires that the object passed is not an rval.
UPD:
Don't forget to specify the trailing return type of forward_args if you use C++11
template<class Function, class ... Args>
auto forward_args(Function f, Args&& ... args) -> decltype(std::ref(f)(std::forward<Args>(args)...))
{
return std::ref(f)(std::forward<Args>(args)...);
}
std::function works because it uses std::invoke which handles calling pointer to member function.
As the solution you could write:
template<class Function, class ... Args>
auto forward_args(Function&& f, Args&& ... args) {
return std::invoke(std::forward<Function>(f), std::forward<Args>(args)...);
}
Syntax for calling member function for an object are:
obj.memberFunction();
obj->memberFunction();
or if you have a pointer to member function:
using Ptr = int (A::*)(int) const;
Ptr p = &A::get;
A a;
(a.*p)(1); // [1]
(obj.*memberFuncPtr)(args...);
the line [1] is valid syntax for calling member function pointed by a pointer. In your case you try A::get(a,2) which is just not valid and cannot work.
Alright, first thing, I still don't understand why forward_args(&A::get, a, 2) doesn't work. Part of the answer was "you need this", but I actually provide it with the second parameter, right ? How is that different from the std::function wrapper ?
On the other hand, while the workarounds proposed in above answer work on the snippet, I actually simplified my original problem too much. I actually need to launch tasks asynchronously, in the following code
thread safety has been removed
yeah, I want to pack all calls in a single data structure, namely tasks, which is wy I start building up wrappers
I don't understand how I can use the proposed solutions to the code below.
#include <iostream>
#include <future>
#include <functional>
#include <queue>
std::queue<std::function<void()>> tasks;
template<class Function, class ... Args>
auto enqueue(Function&& f, Args&& ... args) -> std::future<decltype(f(args...))>
{
std::function<decltype(f(args...))()> func = std::bind(std::forward<Function>(f), std::forward<Args>(args)...);
auto task_ptr = std::make_shared<std::packaged_task<decltype(f(args...))()>>(func);
std::function<void()> wrapper = [task_ptr]() //wrapper to match types of 'tasks'... ugly
{
(*task_ptr)();
};
tasks.push(wrapper);
return task_ptr->get_future();
}
void indep() {}
struct A {
int get(int i) const { return i; }
};
int main()
{
enqueue(indep);
A a;
//enqueue(&A::get, a, 2); //wrong
static auto wrapper_wrong = &A::get;
//enqueue(wrapper_wrong, a, 2); //wrong again
static std::function<int(const A&,int)> wrapper = &A::get;
enqueue(wrapper, a, 2); //ok
static auto autoptr = std::mem_fn(&A::get);
enqueue(autoptr, a, 2); //ok again
}
Someone on stack overflow wrote an interesting way to capture a lambda or functor into your own class. I was trying to simplify it, and I think I got close but was having some trouble. Their example was:
// OT => Object Type
// RT => Return Type
// A ... => Arguments
template<typename OT, typename RT, typename ... A>
struct lambda_expression {
OT _object;
RT(OT::*_function)(A...)const; // A pointer to a member function,
// specifically the operator()
lambda_expression(const OT & object) // Constructor
: _object(object),
_function(&decltype(_object)::operator()) {} // Assigning the function pointer
RT operator() (A ... args) const {
return (_object.*_function)(args...);
}
};
Basically this allows you to go:
int captureMe = 2;
auto lambda = [=](int a, int b) { return a + b + captureMe;};
lambda_expression<decltype(lambda), int, int, int>(lambda);
I was trying to simplify this, and thought that the pointer contained in the lambda_expression class wouldn't be needed, because you can call the function object itself, instead of calling the pointer to the operator(). So I tried this:
template <typename OT, typename ... Args> // No Return type specified
struct lambdaContainer
{
lambdaContainer(OT funcObj) : funcObj(funcObj){ }
OT funcObj; // No pointer, just the function object.
auto operator()(Args... args)
{
return funcObj(args...); // Call the function object directly
}
};
Then something like:
int captureMe = 2;
auto lambda = [=](int a, int b) { return a + b + captureMe; };
lambdaContainer<decltype(lambda), int, int> lam(lambda);
auto i = lam(1, 1);
// i = 4;
Where I wrote the line:
auto operator()(Args... args)
{
return funcObj(args...);
}
Apparently:
decltype(auto) operator()(Args... args) //works in C++14 apparently.
But I tried without the auto keyword and I failed miserably in doing this, I want to understand how the Args... works. I tried:
decltype(funObj(Args...) operator()(Args... args) // this failed
decltype(OT(Args...) operator() (Args... args) // this failed
auto operator() (Args... args) -> decltype(funcObj(Args...)) // this failed
auto operator() (Args... args) -> decltype(OT(Args...)) // this failed
How can I expand the Args parameter so the template can deduce the return type? Is this only possible with auto?
decltype(e) takes an expression e and evaluates to the type of that expression. You need to provide an expression that represents the invocation of your stored lambda:
auto operator()(Args... args)
-> decltype(std::declval<OT>()(std::declval<Args>()...))
In this case, I'm using std::declval to create a "fake instance" of the objects that can be used for deduction purposes, without actually invoking any constructor.
Let's break this down even further:
-> decltype(
std::declval<OT>() // create a fake instance of `OT`
( // invoke it
std::declval<Args>()... // create a fake instance of each argument
// type, expanding `Args...`
)
)
live example on wandbox
By the way, you should still std::forward the arguments in your call to funcObj as there might be some rvalue references that need to be propagated further down:
auto operator()(Args... args)
{
return funcObj(std::forward<Args>(args)...);
}
I'd like to create a function that takes a weak pointer and any kind of functor (lambda, std::function, whatever) and returns a new functor that only executes the original functor when the pointer was not removed in the meantime (so let's assume there is a WeakPointer type with such semantics). This should all work for any functor without having to specify explicitly the functor signature through template parameters or a cast.
EDIT:
Some commenters have pointed out that std::function - which I used in my approach - might not be needed at all and neither might the lambda (though in my original question I also forgot to mention that I need to capture the weak pointer parameter), so any alternative solution that solves the general problem is of course is also highly appreciated, maybe I didn't think enough outside the box and was to focused on using a lambda + std::function. In any case, here goes what I tried so far:
template<typename... ArgumentTypes>
inline std::function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const std::function<void(ArgumentTypes...)>&& fun)
{
return [=] (ArgumentTypes... args)
{
if(pWeakPointer)
{
fun(args...);
}
};
}
This works well without having to explicitly specify the argument types if I pass an std::function, but fails if I pass a lambda expression. I guess this because the std::function constructor ambiguity as asked in this question. In any case, I tried the following helper to be able to capture any kind of function:
template<typename F, typename... ArgumentTypes>
inline function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const F&& fun)
{
return wrap(pWeakPointer, std::function<void(ArgumentTypes...)>(fun));
}
This now works for lambdas that don't have parameters but fails for other ones, since it always instantiates ArgumentTypes... with an empty set.
I can think of two solution to the problem, but didn't manage to implement either of them:
Make sure that the correct std::function (or another Functor helper type) is created for a lambda, i.e. that a lambda with signature R(T1) results in a std::function(R(T1)) so that the ArgumentTypes... will be correctly deduced
Do not put the ArgumentTypes... as a template parameter instead have some other way (boost?) to get the argument pack from the lambda/functor, so I could do something like this:
-
template<typename F>
inline auto wrap(WeakPointer pWeakPointer, const F&& fun) -> std::function<void(arg_pack_from_functor(fun))>
{
return wrap(pWeakPointer, std::function<void(arg_pack_from_functor(fun))(fun));
}
You don't have to use a lambda.
#include <iostream>
#include <type_traits>
template <typename F>
struct Wrapper {
F f;
template <typename... T>
auto operator()(T&&... args) -> typename std::result_of<F(T...)>::type {
std::cout << "calling f with " << sizeof...(args) << " arguments.\n";
return f(std::forward<T>(args)...);
}
};
template <typename F>
Wrapper<F> wrap(F&& f) {
return {std::forward<F>(f)};
}
int main() {
auto f = wrap([](int x, int y) { return x + y; });
std::cout << f(2, 3) << std::endl;
return 0;
}
Assuming the weak pointer takes the place of the first argument, here's how I would do it with a generic lambda (with move captures) and if C++ would allow me to return such a lambda:
template<typename Functor, typename Arg, typename... Args>
auto wrap(Functor&& functor, Arg&& arg)
{
return [functor = std::forward<Functor>(functor)
, arg = std::forward<Arg>(arg)]<typename... Rest>(Rest&&... rest)
{
if(auto e = arg.lock()) {
return functor(*e, std::forward<Rest>(rest)...);
} else {
// Let's handwave this for the time being
}
};
}
It is possible to translate this hypothetical code into actual C++11 code if we manually 'unroll' the generic lambda into a polymorphic functor:
template<typename F, typename Pointer>
struct wrap_type {
F f;
Pointer pointer;
template<typename... Rest>
auto operator()(Rest&&... rest)
-> decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )
{
if(auto p = lock()) {
return f(*p, std::forward<Rest>(rest)...);
} else {
// Handle
}
}
};
template<typename F, typename Pointer>
wrap_type<typename std::decay<F>::type, typename std::decay<Pointer>::type>
wrap(F&& f, Pointer&& pointer)
{ return { std::forward<F>(f), std::forward<Pointer>(pointer) }; }
There are two straightforward options for handling the case where the pointer has expired: either propagate an exception, or return an out-of-band value. In the latter case the return type would become e.g. optional<decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )> and // Handle would become return {};.
Example code to see everything in action.
[ Exercise for the ambitious: improve the code so that it's possible to use auto g = wrap(f, w, 4); auto r = g();. Then, if it's not already the case, improve it further so that auto g = wrap(f, w1, 4, w5); is also possible and 'does the right thing'. ]
I'm trying hard for some hours and didn't manage to get this working.
I have a templated class spinlock:
template<typename T> class spinlock {
// ...
volatile T *shared_memory;
};
I'm trying to create something like this:
// inside spinlock class
template<typename F, typename... Ars>
std::result_of(F(Args...))
exec(F fun, Args&&... args) {
// locks the memory and then executes fun(args...)
};
But I'm trying to use a polymorphic function so that I can do this:
spinlock<int> spin;
int a = spin.exec([]() {
return 10;
});
int b = spin.exec([](int x) {
return x;
}, 10); // argument here, passed as x
// If the signature matches the given arguments to exec() plus
// the shared variable, call it
int c = spin.exec([](volatile int &shared) {
return shared;
}); // no extra arguments, shared becomes the
// variable inside the spinlock class, I need to make
// a function call that matches this as well
// Same thing, matching the signature
int d = spin.exec([](volatile int &shared, int x) {
return shared + x;
}, 10); // extra argument, passed as x... should match too
// Here, there would be an error
int d = spin.exec([](volatile int &shared, int x) {
return shared + x;
}); // since no extra argument was given
Basically, I'm trying to make an exec function that accepts F(Args...) or F(volatile T &, Args...) as an argument.
But I can't manage to make automatic detection of types.
How could I accomplish that?
Firstly, this signature will not compile:
// inside spinlock class
template<typename F, typename... Ars>
std::result_of(F(Args...))
exec(F fun, Args&&... args) {
// locks the memory and then executes fun(args...)
};
The return type needs to be
typename std::result_of<F(Args...)>::type
If your compiler implements N3436 then this function will not participate in overload resolution when fun(args...) is not a valid expression, but that is not required in C++11 and not implemented by many compilers yet. You will need to implement your own SFINAE check to prevent result_of giving an error when fun(args...) is not valid, or rewrite it without result_of
template<typename F, typename... Args>
auto
exec(F fun, Args&&... args) -> decltype(fun(std::forward<Args>(args)...))
{
// locks the memory and then executes fun(args...)
}
Then you can overload it for functions that need the additional parameter passed in:
template<typename F, typename... Args>
auto
exec(F fun, Args&&... args) -> decltype(fun(*this->shared_memory, std::forward<Args>(args)...))
{
// locks the memory and then executes fun(*shared_memory, args...)
}
When fun(std::forward<Args>(args)...) is not valid the first overload will not participate in overload resolution. When fun(*this->shared_memory, std::forward<Args>(args)...) is not valid the second overload will not participate in overload resolution. If neither is valid the call will be ill-formed, if both are valid the call will be ambiguous.