1

I want to create class for binary trees:

struct TreeNode {
    explicit TreeNode(int _value) : value(_value) {}

    int value = 0;
    TreeNode* left = nullptr;
    TreeNode* right = nullptr;
};

class BTree {
    public:
        void Add(int value);
        void PrintPostOrder(void (*func)() = print_current);
        ~BTree();

    private:
        TreeNode* root = nullptr;    
        void print_current();
        void delete_node();
};

BTree::~BTree() {
    PrintPostOrder(delete_node);
}

My idea - for destructor and for Printing I need to do binary tree traversal. So I want to create function Traversal and use function as parameter in it: if I need to print func = print and for destructor func = delete_node.

Error is here:

void PrintPostOrder(void (*func)() = print_current);

the default argument of type "void (BTree :: ) ()" is incompatible with the parameter of type "void () ()"

I don't know how to set default value for parameter when parameter is a function.

1
  • 1
    please do not spam tags, your code is about a tree, but the problem is unrelated to that. I changed the tags, change it back in case you are not happy with it (fwiw, I didnt add the member function pointer tag, because I always find it weird when the tags already have half of the answer) Commented Nov 20, 2019 at 12:53

2 Answers 2

3

print_current and delete_node are member functions, so you need a member function pointer:

class BTree {
public:
    void PostOrder(void (BTree::*fn)() = &BTree::print_current) {
        std::invoke(fn, this);
    }

    ~BTree() {
        PostOrder(&BTree::delete_node);
    }

private:
    void print_current();
    void delete_node();
};

For more flexibility you can make PostOrder a template:

struct TreeNode {};

class BTree {
public:
    template<class Fn>
    void PostOrder(Fn fn) { 
        std::invoke(fn);
    }

    void PostOrder() {
        PostOrder([this] { print_current(); });
    }

    ~BTree() {
        TreeNode* node;
        PostOrder([this, node] { delete_node(node); });
    }

private:
    void print_current();
    void delete_node(TreeNode*);
};
Sign up to request clarification or add additional context in comments.

3 Comments

can I use just void (BTree::*func)() = print_current or I need to use void (BTree::*func)() = &print_current)? Or void (BTree::*func)() = &BTree::print_current) ???
@Mikhail_Sam, unfortunately, it should be that verbose, &BTree::print_current.
I think PrintPostOrder should be named just PostOrder.
3

In principle you set a default parameter for a function the way you did. The problem is that a member function is of different type than a free function.

This is a free function pointer void (*func)(), while print_current is a member function of type void (BTree :: ) ().

Either fix the parameter type or use a free function as default parameter.

Also do not forget that member functions are fundamentally different from free functions, because you need an instance to call them.

4 Comments

Awesome! I got it. Can I ask one more question: what if delete_node function has an argument (pointer to node to delete), but print_current has not. How can I pull function as paramater and it may or may not has an argument?
@Mikhail_Sam, the easiest solution is to make it a template.
@Evg looks like it is another big question. Thank you!
@Mikhail_Sam in that case I would wrap both in a lambda that takes no parameters. Depends of course at what point you know the parameters to be passed. Perhaps better to open another question (in case you cannot find the answer elsewhere)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.