3

I am having issues trying to pass a function as an argument in another object's function. I am well aware there are many similar topics but I either can't get their solution to work or can't understand them.

class foo
{
public:
    void func1(void (*Drawing)(void));

    template<class T>
    void func2(void (T::*Drawing)(void));
};

class bar
{
private:
    foo myFoo;
    void Drawing();
    void func3() {
        // Attempt 1
        myFoo.func1(Drawing);

        // Attempt 2
        myFoo.func2<bar>(&bar::Drawing);
    }
};

So in my first attempt, I get the error where you can't convert void (bar::*)(void) to void (*)(void) of which I then found out there are normal function pointers and member function pointers.

Attempt 2 was my feeble attempt to overcome this but I get unresolved externals now...

So how can I successfully pass my Drawing() member function into another function from another object?

Enriel
  • 61
  • 4
  • 2
    Use function objects, not function pointers. – The Vivandiere Mar 24 '15 at 18:39
  • 5
    You get an unresolved symbol error because you did not provide a definition of `func2`. – Captain Obvlious Mar 24 '15 at 18:40
  • 2
    Can you post the full linker error message? – The Vivandiere Mar 24 '15 at 18:41
  • I don't see how you're supposed to use `&bar::Drawing` in `foo` since it's a private member function. Even given the pointer to the member, the compiler won't let you call it. You can't call it without an instance to work from anyway, so you need to pass `*this` to the function as well. – Austin Mullins Mar 24 '15 at 18:50
  • http://stackoverflow.com/questions/12662891/c-passing-member-function-as-argument – jensa Mar 24 '15 at 18:52
  • 1
    @AustinMullins It's usable in `bar`, and the access control only protects names. And it has a different name in `foo::func2`. Imagine if it worked like you described it - you couldn't even return references to private member variables. – milleniumbug Mar 24 '15 at 18:54
  • @milleniumbug Ah, thanks. I get it now. I was using the wrong calling notation. It works in IDEOne now: http://ideone.com/1LTIDI. – Austin Mullins Mar 24 '15 at 18:57
  • It is not correct that it doesn't work because a definition is missing, you can't call a member function like that. Edit: See the answers below. – jensa Mar 24 '15 at 19:00

2 Answers2

5

The issue is that you cannot consider bar::Drawing as a void (*)(void) function since it's a non static method, which therefore required an object (the this context which will be used)

A solution, assuming c++11 is ok for you, would be to use std::bind and to sligtly modify your foo definition:

class foo
{
    public:
    void func1(std::function<void(void)> Drawing)
    {
        Drawing(); // or do whatever you want with it
    }
};

Then you will be able to do

void bar::func3() {
    myFoo.func1(std::bind(&bar::Drawing, this));
}

making valid a lot of potential uses

int main()
{
    bar myBar;
    myBar.func3();

    foo myFoo;
    myFoo.func1([](){ printf("test\n"); });
    return 0;
}
Amxx
  • 3,020
  • 2
  • 24
  • 45
  • This worked! Thank you very much. Say if I didn't use C++11, was there any other way to solve this problem? – Enriel Mar 28 '15 at 18:45
1

I'm guessing you've left out important details as to what you're trying to accomplish. However, the following should give you some idea of what you need to do.

Code

#include <iostream>

class foo
{
public:
    void func1(void (*Drawing)(void))
    {
        std::cout << "func1\n";
    }

    template<class T>
    void func2(T* instance, void (T::*fn)(void))
    {
        std::cout << "func2: ";
        (instance->*fn)();
    }
};

class bar
{
public:
    bar()
    {
        func3();
    }

private:
    foo myFoo;

    void Drawing()
    {
        std::cout << "bar::Drawing()\n";
    }

    void func3()
    {
        // Attempt 1
        //myFoo.func1(Drawing); // This won't work

        // Attempt 2
        myFoo.func2(this, &bar::Drawing); // Must pass an object instance if you plan to use the member function
    }
};

int main(int argc, char *argv[])
{
    bar b;

    return 0;
}

Sample Output

func2: bar::Drawing()
James Adkison
  • 9,412
  • 2
  • 29
  • 43