2

I have been playing around with function pointers in c++ and seem to have found a bit of a problem. I made a demo to reproduce the error in a simple example.

I have the header file

class MyClass
{
public:
    void MyFunction(int i);
    MyClass();
    ~MyClass();
};

and the cpp file

#include "MyClass.h"
#include <iostream>
#include <functional>
using namespace std;

MyClass::MyClass()
{
    //doesn't work
    function<void(int)> func = &MyClass::MyFunction;
}

void MyClass::MyFunction(int i)
{
    cout << i << endl;
}

In the constructor of the cpp file I am trying to create a pointer to MyFunction. It gives the error error C2664: 'void std::_Func_class<_Ret,int>::_Set(std::_Func_base<_Ret,int> *)' : cannot convert argument 1 from '_Myimpl *' to 'std::_Func_base<_Ret,int> *' in the functional file at line 506. It works fine with a parameterless method, but not with them. Does anyone know why, and how to resolve it?

Trevor M
  • 157
  • 1
  • 11

2 Answers2

3

You can use this and bind the object being constructed to the function. For instance, if your constructor looked like this:

MyClass::MyClass()
{
    function<void(int)> func = bind(&MyClass::MyFunction, this, placeholders::_1);
    func(6);
}

And you created a MyClass instance:

MyClass instance;

Then 6 will be printed to stdout.

huu
  • 7,032
  • 2
  • 34
  • 49
  • This works, thanks. Can you explain what the placeholders::_1 is? – Trevor M Apr 08 '15 at 04:39
  • 1
    The placeholder is basically there as a way of [currying](http://stackoverflow.com/a/160286/2297365) the function. All non-static member functions actually have an implicit first argument, an instance of the class itself. What you're doing is binding an instance to that first argument, leaving the second one unspecified. The placeholder gives you the semantics for expressing this. – huu Apr 08 '15 at 04:41
  • 1
    If for instance, you put a `6` instead of the placeholder, then the function will be fully specified, and you can only call it as `func()`. This would print out a `6` to stdout. – huu Apr 08 '15 at 04:44
3

You can also use std::mem_fn in C++11, which wraps a member function/variable into a callable closure

#include <iostream>
#include <functional>

class MyClass
{
public:
    MyClass()
    {
        auto func = std::mem_fn(&MyClass::MyFunction);
        func(this, 42); // call it on the current instance
    }
    void MyFunction(int i)
    {
        std::cout << i << std::endl;
    }
};

int main()
{
    MyClass foo;
}

or, you can explicitly specify the instance you're calling the pointer to member function

MyClass()
{
    auto func = &MyClass::MyFunction;
    (this->*func)(42); // call it on the current instance
}

In particular, note that std::function<void(int)> is not convertible to a pointer to member function. See related Using generic std::function objects with member functions in one class That's why using auto with std::mem_fn gets rid of all the pain.

Community
  • 1
  • 1
vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • 1
    This is a great answer. It lets you treat the function as C++ treats it, as a function taking an instance of the class as the first argument, and all the other arguments following it. – huu Apr 08 '15 at 04:56
  • Thanks, I found relatively recently about `std::mem_fn`, I think it's a great wrapper for day-to-day C++ work – vsoftco Apr 08 '15 at 04:58