1

I have a problem with storing lambda expression with capturing "this" pointer in class as parameter. I made typedef like this:

typedef void(*func)();

This code below works fine.

#include <iostream>
using namespace std;

typedef void(*func)();

class A {
public:
    func f;
};

class B {
public:
    A *a;

    B() {
        a = new A();
        a->f = [](){
            printf("Hello!");
        };
    }
};

int main() {
    B *b = new B();
    b->a->f();
    return 0;
}

There is no capturing yet but when I want to capture "this" pointer in lambda it throws an error. How can I make typedef with capturing? I want to do something like this:

#include <iostream>
using namespace std;

typedef void(*func)();

class A {
public:
    func f;
};

class B {
public:
    A *a;

    B() {
        a = new A();

        //There is a problem with [this]
        a->f = [this](){
            //Method from class B using "this" pointer
            this->p();
        };
    }
    void p() {
        printf("Hello!");
    }
};

int main() {
    B *b = new B();
    b->a->f();
    return 0;
}

What am I doing wrong? Explain me please. Thanks.

hmjd
  • 117,013
  • 19
  • 199
  • 247
eSeverus
  • 552
  • 1
  • 5
  • 17

2 Answers2

5

It is not possible to convert from a lambda with a capture to a function pointer, because a lambda with a capture contains more information than a function pointer (it contains not only the address of the function, but also the variables that have been captured).

Change typedef void(*func)(); to typedef std::function<void()> func; to get something which is able to hold any copyable function type.

Mankarse
  • 38,538
  • 10
  • 94
  • 140
3

As Angew said above, you should be using the std::function class template, not just a function pointer. Your code would become this (copying from 2nd example)

#include <iostream>
#include <functional>
#include <memory>
using namespace std;



class A {
public:
    std::function<void> f;
};

class B {
public:
    shared_ptr<A> a;  // Better ownership

    B() 
     : a(new A())
    {
        // Now this should work
        a->f = [this](){
            //Method from class B using "this" pointer
            this->p();
        };
        // Note, you could just do this instead of a lambda:
        // a->f = bind(b::p, this);
    }
    void p() {
        printf("Hello!");
    }
};

int main() {
    B *b = new B();
    b->a->f();
    return 0;
}

I also added automatic cleanup of A via a smart pointer, in addition to the correct callable object, and added the code to show you how to do this with std::bind as well.

Kevin Anderson
  • 6,441
  • 4
  • 31
  • 54