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
  • 120,187
  • 20
  • 207
  • 252
eSeverus
  • 552
  • 1
  • 6
  • 18

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
  • 39,818
  • 11
  • 97
  • 141
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,850
  • 4
  • 32
  • 54