Passing References to Member Functions

182 views Asked by At

I've been working with a doubly-threaded BST in C++, and I thought it would be cool to separate my visitor functions from my various traversals. However I can't figure out how to properly pass references to member functions into my traversal functions. Here is a massively simplified version of my problem:

class foo {
public:
    foo() {};
    ~foo() {};

    void print(int x) const { //visitor
        cout << x << endl;
    }

    void traverse(void (*visitor)(int)) { //traversal
        for (int i = 0; i < 9; i++)
            visitor(myAry[i]);
    }

    void printAll() { //function calling the traversal and passing it a reference to the visitor
        traverse(&print);
    }

    int myAry[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
};

The problem of course comes in the traverse(&print); statement.

Any clues what's going wrong, or what I could try differently to achieve the same effect?

2

There are 2 answers

3
Sam Varshavchik On BEST ANSWER
void (*visitor)(int)

In C++ this means: a pointer to a function that takes an int parameter and returns a void.

&print

The type of this expression is not "a pointer to a function that takes an int parameter and returns a void". It is "a pointer to a method of class foo that takes an int parameter and returns a void".

Class methods and functions are not the same thing. They might look the same, but they're not.

In your sample code you don't need to use a class method, for print, so just declare it as a static class member:

static void print(int x) const {
    cout << x << endl;
}

And, with no other changes, this should work, since this is now a function. The difference between a class method is a function is that a class method requires an object whose method gets invoked.

It's possible that your clear code does really require a pointer to a class method. In which case traverse() should probably be something like:

void traverse(void (*foo::visitor)(int)) {
    for (int i = 0; i < 9; i++)
        (this->*visitor)(myAry[i]);
}

and this would be invoked as

traverse(&foo::print);

This is because void (*foo::visitor)(int) means "a pointer to a method of class foo that takes an int parameter and returns a void". And this is what your print is.

1
Ted Lyngmo On

You must specify the class and which instance to call the function on. Also make sure that the signatures match.

void traverse(void(foo::*visitor)(int) const) {
//                 ^^^^^               ^^^^^
    for (int i = 0; i < 9; i++)
        (this->*visitor)(myAry[i]);
//       ^^^^^^
}

void printAll() {
    traverse(&foo::print);
//            ^^^^^
}