C++11 lambda capture by copy unless wrapped in std::ref - c++

When passing the arguments to std::bind they are always copied or moved, unless wrapped by std::ref and I want to do the same with a lambda expression.
The Problem is, that I want to wrap the generation of the lambda expression in a function and forward the arguments as passed by the user to the lambda. The reason I want to do this, is that I want to call the lambda asynchronously and let the user decide if the arguments shall be passed by reference or by copy.
Consider the following example. I have the function print_address that takes the parameter as reference. Then I have the function combine_and_call_bind that forwards the arguments into std::bind.
void print_address(int& a) {
std::cout << "Adress of a = " << &a << std::endl;
}
template<typename F, typename Args>
void combine_and_call_bind(F f, Args&& args) {
auto a = std::bind(f, std::forward<Args>(args));
a();
}
The user can the specify when calling the combine_and_call_bind-function if the arguments shall be copied into std::bind or if they shall be passed by reference by wrapping the arguments in std::ref:
combine_and_call_bind(print_address, a); // copy a into std::bind
combine_and_call_bind(print_address, std::ref(a)); // pass a as reference into std::bind
How can I do the same with the following function combine_and_call_lambda, while using C++11?
template<typename F, typename Args>
void combine_and_call_lambda(F f, Args&& args) {
auto a = [/* std::forward<Args>(args) */, f] {
f(args);
};
a();
}

You might try to capture everything by value:
template<typename F, typename... Args>
void combine_and_call_lambda(F f, Args&&... args) {
auto a = [=]() mutable {
f(args...);
};
a();
}
Then use:
combine_and_call_lambda(print_address, a);
combine_and_call_lambda(print_address, std::ref(a));
DEMO
As we can see at lambda:
captures - a comma-separated list of zero or more captures, optionally
beginning with a capture-default.
Capture list can be passed as follows (see below for the detailed
description):
...
[=] captures all automatic variables used in the body of the lambda
by copy and current object by reference if exists
So, in the code above everything is copied and stored inside the lambda object.

Related

To transform std::bind to std::function?

See the code below
queue<function<void()> > tasks;
void add_job(function<void(void*)> func, void* arg) {
function<void()> f = bind(func, arg)();
tasks.push( f );
}
func is the function I want to add to the tasks which has argument is arg.
How can I do to use std::bind to bind its argument so that it can be assigned to the object of std::function<void()>?
How can I do to use std::bind to bind its argument so that it can be assigned to the object of function<void()>?
The std::bind returns an unspecified callable object, which can be stored in the std::function directly. Therefore you required only
function<void()> f = bind(func, arg); // no need to invoke the callable object
tasks.push( f );
However, I would recommend using lambdas (since C++11) instead of std::bind.
Secondly, having global variables are also not a good practice. I would propose the following example code. Let the compiler deduce the type of the passed functions and their (variadic) arguments (function-template).
template<typename Callable, typename... Args>
void add_job(Callable&& func, Args const&... args)
{
// statically local to the function
static std::queue<std::function<void()>> tasks;
// bind the arguments to the func and push to queue
tasks.push([=] { return func(args...); });
}
void fun1(){}
void fun2(int){}
int main()
{
add_job(&fun1);
add_job(&fun2, 1);
add_job([]{}); // passing lambdas are also possible
}
See a demo in
Just bind it, don't execute it.
function<void()> f = bind(func, arg);
tasks.push( f );

properly forward a parameter pack in a lambda without discarding qualifiers

I am trying to store lambda functions in a queue to execute them later. In order to do that, i am trying to hide the parameter pack in a lambda without losing scope so I can still access the passed arguments in an upper scope.
Sadly I cannot compile this since the parameter pack does not match the const qualifier.
I hope it is easier to understand what I am trying to accomplish by looking at the following code. (I am using c++17, not c++20).
I think I misunderstand how to properly forward the variadic parameter pack since as I do it right now, the binding reference to const will discard qualifiers.
It is sadly not an option to expect the parameters in the functional lambda to be const.
std::queue<std::function<void()>> fcts;
template<typename F >
auto push_fct(F &task) -> void {
// Do things
fcts.push(std::move(std::function<void()>(task)));
}
template<typename F, typename... A>
auto push_fct(F& task , A&... args) -> void {
push_fct( [task, args...] { task(args...);});
}
auto main() -> int {
auto functional = [&](class_a & a, class_b & b) {
a.memberFct();
b.memberFunction(123);
}
class_a instance_a;
class_b instance_b;
push_fct(functional, instance_a, instance_b);
return 0;
}
What happens is, here [task, args...] the references are lost; task, args... are captured by value, which, in a non-mutable lambda additionally become const, which subsequently can't bind to non-const references in the call to [&](class_a & a, class_b & b).
You can capture the references by reference. Don't worry about their lifetime - the references are collapsed, and the original ones will be captured (source).
template<typename F>
auto push_fct(F&& task) -> void {
// Do things
fcts.emplace(std::forward<F>(task));
}
template<typename F, typename... A>
auto push_fct(F& task, A&... args) -> void {
push_fct([&task, &args...]{ task(args...); });
}

Is it safe to pass const reference to temporary/annonymous lambda into std::thread constructor?

Following on from this question: can-a-temperary-lambda-by-passed-by-reference?
I have a fixed code snippet:
// global variable
std::thread worker_thread;
// Template function
template <typename Functor>
void start_work(const Functor &worker_fn) // lambda passed by const ref
{
worker_thread = std::thread([&](){
worker_fn();
});
}
This is called like this:
void do_work(int value)
{
printf("Hello from worker\r\n");
}
int main()
{
// This lambda is a temporary variable...
start_work([](int value){ do_work(value) });
}
This seems to work, but I am concerned about passing a temporary lambda into the thread constructor since the thread will run, but the function start_work() will return and the temp-lambda will go out of scope.
However I was looking at the std::thread constructor which is defined:
thread() noexcept; (1) (since C++11)
thread( thread&& other ) noexcept; (2) (since C++11)
template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args ); (3) (since C++11)
thread(const thread&) = delete; (4) (since C++11)
So I am assuming that the constructor 3 is called:
template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );
I struggle to understand what is written here, but it looks like it would try to move the lambda && which I believe is ok for temp variables.
So is what I have done in my code snippet dangerous (i.e. the ref goes out of scope) or correct (i.e. the temp is moved and all is well)? or neither??
An alternative is to just pass my value (make a copy) which is not so bad anyway in this case.
A temporary is indeed moved but it is the "inner" one, the argument to std::thread.
That temporary holds a reference to the "outer" temporary, the argument to start_work, and whose lifetime ends after start_work has returned.
Thus, your "inner" lambda object holds a reference to an object that may or may not exist during its execution, which is very unsafe.
A lambda is an anonymous struct in C++. If we were to translate the snippet to an equivalent one without lambdas, it would become
template <typename Functor>
void start_work(const Functor &worker_fn)
{
struct lambda {
const Functor& worker_fn;
auto operator()() const { worker_fn(); }
};
worker_thread = std::thread(lambda{worker_fn});
}
lambda has a non-stack-based const reference as a member, which would dangle as soon as start_work returns, regardless whether the lambda object itself is copied.

c++14 Variadic lambda capture for function binding

I'm currently reading a few books to get caught up on c++14 features. I am trying to use a variadic template to bind arguments to a function. I know how to do this using std::bind, but I would also like to implement this function with a c++14 lambda expression, just for common knowledge and understanding, and for any possible performance benefits. I've read that lambdas can be inlined while std::bind cannot inline because it takes place through a call to a function pointer.
Here is the code from myFunctions.h:
#include <functional>
int simpleAdd(int x, int y) {
return x + y;
}
//function signatures
template<class Func, class... Args>
decltype(auto) funcBind(Func&& func, Args&&...args);
template<class Func, class... Args>
decltype(auto) funcLambda(Func&& func, Args&&...args);
/////////////////////////////////////////////////////////////////
//function definitions
template<class Func, class... Args>
inline decltype(auto) funcBind(Func&& func, Args&&... args)
{
return bind(forward<Func>(func), forward<Args>(args)...);
}
template<class Func, class ...Args>
inline decltype(auto) funcLambda(Func && func, Args && ...args)
{ //The error is caused by the lambda below:
return [func, args...]() {
forward<Func>(func)(forward<Args>(args)...);
};
}
Here is the main code I am running:
#include<iostream>
#include<functional>
#include "myFunctions.h"
using namespace std;
int main()
{
cout << "Application start" << endl;
cout << simpleAdd(5,7) << endl;
auto f1 = funcBind(simpleAdd,3, 4);
cout << f1() << endl;
//error is occurring below
auto f2 = funcLambda(simpleAdd, 10, -2);
cout << f2() << endl;
cout << "Application complete" << endl;
Error C2665 'std::forward': none of the 2 overloads could convert all the argument types
Error C2198 'int (__cdecl &)(int,int)': too few arguments for call
I think the error might be occurring when the variadic arguments are getting forwarded to the lambda, but I'm not really sure.
My question is how do I properly formulate this code so that I can use a lambda to capture the function and its arguments, and call it later.
I've read that lambdas can be inlined while std::bind cannot inline
because it takes place through a call to a function pointer.
If you pass simpleAdd to something that then binds the arguments, then whether you use bind or not doesn't matter. What do you think the lambda captures with func? It's a function pointer.
The lambda-vs-function-pointer case is about writing bind(simpleAdd, 2, 3) vs. [] { return simpleAdd(2, 3); }. Or binding a lambda like [](auto&&...args) -> decltype(auto) { return simpleAdd(decltype(args)(args)...); } vs. binding simpleAdd directly (which will use a function pointer).
In any event, implementing it is surprisingly tricky. You can't use by-reference capture because things can easily get dangling, you can't use a simple by-value capture because that would always copy the arguments even for rvalues, and you can't do a pack expansion in an init-capture.
This follows std::bind's semantics (invoking the function object and passing all bound arguments as lvalues) except that 1) it doesn't handle placeholders or nested binds, and 2) the function call operator is always const:
template<class Func, class ...Args>
inline decltype(auto) funcLambda(Func && func, Args && ...args)
{
return [func = std::forward<Func>(func),
args = std::make_tuple(std::forward<Args>(args)...)] {
return std::experimental::apply(func, args);
};
}
cppreference has an implementation of std::experimental::apply.
Note that this does unwrap reference_wrappers, like bind, because make_tuple does it.
Your original code breaks down because args are const in the lambda's function call operator (which is const by default), and the forward ends up attempting to cast away constness.
You use a tuple:
template<class Func, class ...Args>
inline decltype(auto) funcLambda(Func && func, Args && ...args)
{ //The error is caused by the lambda below:
auto tpl = make_tuple(std::forward<Args>(args)...);
//Use move just in case Args has move-only types.
return [func, tpl = move(tpl)]() {
apply(func, tpl);
};
}
Where apply is defined something like this:
namespace detail {
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl( F&& f, Tuple&& t, std::index_sequence<I...> )
{
return f(std::get<I>(std::forward<Tuple>(t))...);
}
} // namespace detail
template <class F, class Tuple>
constexpr decltype(auto) apply(F&& f, Tuple&& t)
{
return detail::apply_impl(std::forward<F>(f), std::forward<Tuple>(t),
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>>::value);
}
apply is a feature of one of the library TS versions. With C++17, apply_impl could call invoke, which would work for any callable.

How to bind variadic template params to function

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?