0

I want to save lambda expressions variables (like in the fist code block). The problem is that then I use a classes (like the second code block) the compiler return me some errors. I don"t know how to fix it.

I hope somebody can help me and explain, why it's not working like this. Thanks.

First Code:

// variable for function pointer
void (*func)(int);
// default output function
void my_default(int x) {
    cout << "x =" << "\t" << x << endl << endl;
}


int main() {
    cout << "Test Programm\n\n";

    // 1. Test - default output function
    cout << "my_default\n";
    func = &my_default;
    func(5);

    // 2. Test - special output function 2
    cout << "my_func2\n";
    func = [](int x) {  cout << "x =" << "  " << x << endl << endl; };
    func(5);

    return 0;
}

Second Code:

class test {
private:
    // variable for function pointer
    void (*func)(int);
    // default output function
    void my_default(int x) {
        cout << "x =" << "\t" << x << endl << endl;
    }

public:
    void dummy(void) {
        // 1. Test - default output function
        cout << "my_default\n";
        func = &my_default;
        func(5);

        // 2. Test - special output function 2
        cout << "my_func2\n";
        func =  [](int x)->int{ cout << "x =" << "  " << x << endl << endl; };
        func(5);
    }
};


// entry
int main() {
    cout << "Test Programm\n\n";

    test a;
    a.dummy();

    return 0;
}

Compiler:

pi@raspberrypi ~/dev/property $ gcc -std=c++0x -o test2 test2.cpp -lstdc++
test2.cpp: In member function ‘void test::dummy()’:
test2.cpp:491:17: error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.  Say ‘&test::my_default’ [-fpermissive]
test2.cpp:491:17: error: cannot convert ‘void (test::*)(int)’ to ‘void (*)(int)’ in assignment
test2.cpp:496:77: error: invalid user-defined conversion from ‘test::dummy()::<lambda(int)>’ to ‘void (*)(int)’ [-fpermissive]
test2.cpp:496:28: note: candidate is: test::dummy()::<lambda(int)>::operator int (*)(int)() const <near match>
test2.cpp:496:28: note:   no known conversion for implicit ‘this’ parameter from ‘int (*)(int)’ to ‘void (*)(int)’
Heinrich
  • 307
  • 4
  • 12
  • 1
    Member function pointers are not the same as function pointers. You can see in the error that the types are different. – chris Jan 28 '14 at 20:16
  • In addition to the answers below... Your lambda in test2.cpp is failing because it returns int instead of void. – Rastaban Jan 29 '14 at 17:24

2 Answers2

1

The problem is that member functions are not normal functions, they can't be assigned to a function pointer because the type in which they are member is part of their type. Also, a member function needs to have an object to be called on, which will be the this inside the function code.

You have several solutions:

  1. allow only functions which are member of your class

    void (*MyClass::func)(int); // but you can use it only with members of the class
    
  2. use std::function

    typedef std::function<void(int)> func;
    

The solution 2 is the simplest as std::function is designed to work with anything that is callable with the same signature as the one in the template parammetters. Also, it's the only solution that allows you to store closures(objects from lambdas). See C++11 styled callbacks? for details.

class test {
private:
    // variable for function pointer
    std::function< void ( int )> func;
    // default output function
    void my_default(int x) {
        cout << "x =" << "\t" << x << endl << endl;
    }

public:
    void dummy(void) {
        // 1. Test - default output function
        cout << "my_default\n";
        func = std::bind(&test::my_default, this, std::placeholders::_1);
        // or 
        func = [&]( int i ){ my_default( i ); };
        func(5);

        // 2. Test - special output function 2
        cout << "my_func2\n";
        func =  [](int x)->int{ cout << "x =" << "  " << x << endl << endl; };
        func(5);
    }
};


// entry
int main() {
    cout << "Test Programm\n\n";

    test a;
    a.dummy();

    return 0;
}
Community
  • 1
  • 1
Klaim
  • 67,274
  • 36
  • 133
  • 188
  • Thank you for the explanation. "func = std::bind( &my_default, this );" will return errors (compiler) but like Brian Bi wrote "std::bind(&test::my_default, this, std::placeholders::_1);" will return no errors. – Heinrich Jan 28 '14 at 21:01
  • Ah yes I always have a hard time reminding how to use bind, so I just use lambdas. Also, there is `mem_fun()`. – Klaim Jan 28 '14 at 21:11
  • I recommend the `std::function` route, although a third option (depending on the nature of `my_default`) is to make `my_default` static. – Rastaban Jan 29 '14 at 17:26
  • @Rastaban He want to use lambdas, and we don't know it it's capturing lambdas or not. – Klaim Jan 29 '14 at 18:04
0

A member function is not like an ordinary function, in that there has to be an instance of the class available in order to invoke it (i.e., the object that will become *this). You can't make an ordinary function pointer variable point to a member function.

If you want to create a function pointer that can be called using any instance of the class, you need a member function pointer. You would write

void (test::*func)(int);

to declare it,

func = &test::my_default;

to assign it, and

(this->*func)(5);

to call it. Of course, now you can't make a member function pointer point to a lambda.

If on the other hand you want to bind this as the instance and create an ordinary function from a member function, well, you can't actually make an ordinary function pointer to it. Instead you'll want an std::function object,

std::function<void(int)> func;

bind as follows:

func = std::bind(&test::my_default, this, std::placeholders::_1);

and then call normally. std::function works with lambdas just like a function pointer would.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • Thank you!! I probably forgotten what the difference between a member function and an ordinary function is. – Heinrich Jan 28 '14 at 21:06