Rebinding lambda in c++11... is it possible? - c++

I have a situation where I have a lambda as a member variable that is created by a certain function call. The problem is that it captures this as a part of its operation. Later on, I want to be able to copy the whole object...
However, at the time of the copy I don't know how the lambda was created (it could have been defined in several spots through different code paths). Hence, I'm somewhat at a loss as to what to put in the copy constructor. Ideally, I would want to "rebind" the lambda's captures to the new "this" that was created.
Is this at all possible?
Here's some sample code:
#include <iostream>
#include <string>
#include <functional>
class Foo
{
public:
Foo () = default;
~Foo () = default;
void set (const std::string & v)
{
value = v;
}
void set ()
{
lambda = [&]()
{
return this->value;
};
}
std::string get ()
{
return lambda();
}
std::string value;
std::function <std::string (void)> lambda;
};
int main ()
{
Foo foo;
foo.set ();
foo.set ("first");
std::cerr << foo.get () << std::endl; // prints "first"
foo.set ("captures change");
std::cerr << foo.get () << std::endl; // prints "captures change"
Foo foo2 (foo);
foo2.set ("second");
std::cerr << foo.get () << std::endl; // prints "captures change" (as desired)
std::cerr << foo2.get () << std::endl; // prints "captures change" (I would want "second" here)
return 0;
}
Thanks in advance.

The problem you're seeing is that the this pointer is being captured into the lambda, but you're now executing the copy of the function from another object. It's working in your example because both objects exist, but it's a dangling pointer waiting to happen.
The cleanest way to do this is to modify your std::function and your lambdas to take an argument of a pointer to the class, and use that passed in pointer instead of capturing this. Depending on the contents of your lambda, you can choose to capture the values.
class Foo
{
public:
Foo () = default;
~Foo () = default;
void set (const std::string & v)
{
value = v;
}
void set ()
{
lambda = [](Foo* self)
{
return self->value;
};
}
std::string get ()
{
return lambda(this);
}
std::string value;
std::function <std::string (Foo*)> lambda;
};
Example at IDEOne

I don't think you can modify the closure. If you need the function to operate on another object, you need to pass the pointer to the object as an argument to the function:
class Foo
{
public:
Foo () = default;
~Foo () = default;
void set (const std::string & v)
{
value = v;
}
void set ()
{
lambda = [](Foo* t)
{
return t->value;
};
}
std::string get ()
{
return lambda(this);
}
std::string value;
std::function <std::string (Foo*)> lambda;
};

Related

Call a C-style function address with std::bind and std::function.target using a method from object

I have a C-style function, which stores another function as an argument. I also have an object, which stores a method that must be passed to the aforementioned function. I built an example, to simulate the desired situation:
#include <functional>
#include <iostream>
void foo(void(*f)(int)) {
f(2);
}
class TestClass {
public:
std::function<void(int)> f;
void foo(int i) {
std::cout << i << "\n";
}
};
int main() {
TestClass t;
t.f = std::bind(&TestClass::foo, &t, std::placeholders::_1);
foo( t.f.target<void(int)>() );
return 0;
}
What is expected is that it will be shown on screen "2". But I'm having trouble compiling the code, getting the following message on the compiler:
error: const_cast to 'void *(*)(int)', which is not a reference, pointer-to-object, or pointer-to-data-member
return const_cast<_Functor*>(__func);
As I understand the use of "target", it should return a pointer in the format void () (int), related to the desired function through std :: bind. Why didn't the compiler understand it that way, and if it is not possible to use "target" to apply what I want, what would be the alternatives? I don't necessarily need to use std :: function, but I do need the method to be non-static.
This is a dirty little hack but should work
void foo(void(*f)(int)) {
f(2);
}
class TestClass {
public:
void foo(int i) {
std::cout << i << "\n";
}
};
static TestClass* global_variable_hack = nullptr;
void hacky_function(int x) {
global_variable_hack->foo(x);
}
int main() {
TestClass t;
global_variable_hack = &t;
foo(hacky_function);
return 0;
}
//can also be done with a lambda without the global stuff
int main() {
static TestClass t;
auto func = [](int x) {
t->foo(x); //does not need to be captured as it is static
};
foo(func); //non-capturing lambas are implicitly convertible to free functions
}

Get reference to member function overloaded by const specification

Here is some class with two overloaded methods foo:
class Object {
public:
Object (double someVal) : val(someVal) { }
double getter () const { return val; }
double& getter () { return val; }
private:
double val;
};
So now the double Object::getter() const function will be called on const instances
const Object instance(42);
cout << instance.getter() << endl; // called: `double getter() const`
Now, I am trying to get reference to double getter() const function and assign it to std::function type
const Object instance(42);
function<double(const Object&)> foo = &Object::getter;
cout << foo(instance) << endl;
The code works fine if function double& getter() is removed, but with it I got the following error on the second line:
test.cpp:18:34: error: no viable conversion from '<overloaded function type>' to
'function<double (const Object &)>'
function<double(const Object&)> foo = &Object::getter;
^ ~~~~~~~~~~~~~~~
It seems that error happens, because system tries to call double& getter().
The question is how to force calling of double getter() const?
The full listing is attached here
By casting to the specific function pointer type:
std::function<double(const Object&)> foo = static_cast<double(Object::*)() const>(&Object::getter);
Just use a lambda closure:
Object o{0.0};
std::function<double()> f = [o](){ return o.getter(); };
The lambda calls the const version of getter(), as captured variables are const by default (otherwise you'd have to use mutable).
Address of Overload functions defined 7 contexts where the correct overload can be deduced. Yet std::function<...> is not one of them. Thus, the overload function to get address of is ambiguous.
There are a few ways to select the overload you want:
const Object instance(42);
// Use static_cast to select overload
std::function<double(const Object&)> foo = static_cast<double(Object::*)() const>(&Object::getter);
// Use lambda to select overload
// std::function type parameters can be omitted since c++ 17
// Guaranteed copy elision since c++ 17
std::function bar = [](const Object& instance) { return instance.getter(); };
// Use std::mem_fn
std::function<double(const Object&)> mfn = std::mem_fn<double() const>(&Object::getter);
However, an idiomatic way to declare methods with similar functionality but differed by constness is actually to declare two different functions: foo() and cfoo(). Think about begin() and cbegin(). The latter returns a const iterator.
You can use a typedef to disambiguate the function you want:
#include <iostream>
#include <functional>
class Object {
public:
Object (double someVal) : val(someVal) { }
double getter () const { return val; }
double& getter () { return val; }
private:
double val;
};
typedef double (Object::*funtype)() const;
int main()
{
const Object instance(42);
std::function<double(const Object&)> foo = static_cast<funtype>(&Object::getter);
std::cout << foo(instance) << std::endl;
}
run on cpp.sh
Or, without casting:
#include <iostream>
#include <functional>
class Object {
public:
Object (double someVal) : val(someVal) { }
double getter () const { return val; }
double& getter () { return val; }
private:
double val;
};
typedef double (Object::*funtype)() const;
int main()
{
const Object instance(42);
funtype temp = &Object::getter;
std::function<double(const Object&)> foo = temp;
std::cout << foo(instance) << std::endl;
}
run on cpp.sh
Yet another example, going through some options.
// auto mem_fn = static_cast<double (Object::*)() const>(&Object::getter);
// or shorter:
double (Object::*mem_fn)() const = &Object::getter;
// store member function (without instance)
std::function<double(const Object&)> foo = mem_fn;
std::cout << foo(instance) << "\n";
// bind with instance
auto bound = std::bind(mem_fn, &instance);
std::cout << bound() << "\n";
// store member function (with instance)
std::function<double()> bar = bound;
std::cout << bar() << "\n";
// store member function (with instance), without the intermediate steps
std::function<double()> baz =
std::bind(
static_cast<double (Object::*)() const>(&Object::getter),
instance
);
std::cout << baz() << "\n";

How to pass a private member function as an argument

In ROS, there is a function called NodeHanle::subscribe(Args...): NodeHandle::subscribe. Which lets u pass a PRIVATE member function as callback.
However, when I tried it myself (passing private member function using std::bind), my compiler always fails and complaining about Foo::foo() is a private member function. When I change Foo::foo to public function, everything goes to normal.
template<typename T>
void getWrapper1(void(T::*fn)(int), T *t) {
return [&](int arg) {
std::cout << "process before function with wrapper" << std::endl;
(t->*fn)(arg);
std::cout << "process after function with wrapper" << std::endl;
};
}
void getWrapper2(std::function<void(int)> fn) {
return [=](int arg) {
std::cout << "process before function with wrapper" << std::endl;
fn(arg);
std::cout << "process after function with wrapper" << std::endl;
}
}
class Foo {
private:
void foo(int a) {
std::cout << __FUNCTION__ << a << std::endl;
}
}
int main(int argc, char** argv) {
Foo foo_inst;
auto func1 = getWrapper1(&Foo::foo, &foo_inst); // fail because foo is private
auto func2 = getWrapper2(std::bind(&Foo::foo, &foo_inst, std::placeholders::_1)); // fail because foo is private
func1(1);
func2(2);
return 0;
}
from this answer, using std::function can also passing private member function. But what I tried it different.
It worths to mention that in getWrapper2 I use [=] instead of [&] because using [&] may cause seg fault. Why it has to be a "value capture"?
platform: GCC 5.4.0, c++14, ubuntu16.04
You must pass it from the inside. You cannot access private function from the outside of the class. Not even pointer to private stuff. Private is private.
class Foo {
void foo(int a) {
std::cout << __FUNCTION__ << a << std::endl;
}
public:
auto getWrapper() {
// using a lambda (recommended)
return getWrapper2([this](int a) {
return foo(a);
});
// using a bind (less recommended)
return getWrapper2(std::bind(&Foo::foo, this, std::placeholders::_1));
}
}
Why it has to be a "value capture"?
Both wrapper need to value capture. Your Wrapper1 have undefined behaviour.
Consider this:
// returns a reference to int
auto test(int a) -> int& {
// we return the local variable 'a'
return a;
// a dies when returning
}
The same thing happen with a lambda:
auto test(int a) {
// we capture the local variable 'a'
return [&a]{};
// a dies when returning
}
auto l = test(1);
// l contain a captured reference to 'a', which is dead
Pointers are passed by value. A pointer is itself an object. A pointer has itself a lifetime and can die.
auto test(int* a) -> int*& {
// we are still returning a reference to local variable 'a'.
return a;
}
And... you guessed it, the same thing for std::function:
auto test(std::function<void(int)> a) {
// return a lambda capturing a reference to local variable 'a'.
return [&a]{};
}

When to use this for class function in lambda

When should this be used in a lambda to call a class member function? I have an example below, where hello(); is called without this but this->goodbye(); does:
#include <iostream>
class A
{
void hello() { std::cout << "hello" << std::endl; }
void goodbye() { std::cout << "goodbye" << std::endl; }
public:
void greet()
{
auto hi = [this] () { hello(); }; // Don't need this.
auto bye = [this] () { this->goodbye(); }; // Using this.
hi();
bye();
}
};
int main()
{
A a;
a.greet();
return 0;
}
Is there any advantage to one way over the other?
Edit: The lambda for hello does not capture anything, yet it inherits functions that exist in the class scope. It cannot do this for members, why can it do this for functions?
this is more explicit and more verbose.
but it might be also required with variables which hide member (capture or argument):
auto goodbye = [](){}; // Hide method
auto bye = [=] (int hello) {
this->goodbye(); // call method
goodbye(); // call above lambda.
this->hello(); // call method
std::cout << 2 * hello; // show int parameter.
};

C++ Add to the end of a lambda

I'm trying to add a line of code to the end of a lambda, similar to what the += operator does to std::string. For instance:
std::function<void()> foo = []() {
std::cout << "User defined code\n";
};
foo += [](){ std::cout << "I added this"; };
Desired output after calling foo():
User defined code
I added this
Of course this does not actually work as written.
Is this possible, or is there another way to effectively accomplish the same thing? Perhaps copying the lambda to another std::function then pass by value to a new lambda or something?
Edit:
I'm working with a class with a std::function member (foo) initialized with a lambda. Its member functions call it directly (with foo()) and I need to make it so that every time foo is called, an additional function is called as well. However this can be done would be great, as long as foo can still be called with foo();.
If you can change the type of the member, something like this might do it:
class Functions
{
public:
using Function = std::function<void()>;
Functions() = default;
template<typename Fn>
Functions(Fn f) { functions.push_back(f); }
Functions& operator+=(Function f)
{
functions.push_back(f);
return *this;
}
void operator()()
{
for (auto& f: functions)
{
f();
}
}
private:
std::vector<Function> functions;
};
Functions foo = []() { cout << "Hello"; }
foo += []() { cout << ", world!"; };
foo();
This solution is the closest I could come up with for your problem at hand:
class Lambdas
{
vector<function<void()>> lambdas;
public:
Lambdas(function<void()> lamb)
{
lambdas.push_back(lamb);
}
Lambdas& operator+=(function<void()> lamb)
{
lambdas.push_back(lamb);
return *this;
}
void operator()()
{
for (int i = 0; i<lambdas.size(); i++)
{
lambdas[i]();
}
}
};
Hope this helps.