0

I implemented some basic functionality for adding data to binary tree. I wanted to practice async calls and therefore I decided to implement Node adding as async task. However, I get build errors on the line that calls async task. Here is the sample code:

struct Node
{
    static Node *root;
    static mutex _mtx;
    int _value;
    Node *_left;
    Node *_right;

    Node()
    {
        _left = nullptr;
        _right = nullptr;
    }

    Node(int value)
    {       
        _left = nullptr;
        _right = nullptr;
        _value = value;

        if (!root) root = this;
        else
        {
            lock_guard<mutex> lck(_mtx);
            auto func = bind(&Node::AddNodeAsync, root, ref(*this));
            auto ftr = async(launch::async, func); // Error!!!!!!       
        }
    }

    void AddNodeAsync(Node *parentNode, Node &nodeToAdd)
    {
        lock_guard<mutex> lck(_mtx);
        AddNode(parentNode, nodeToAdd);
    }

    void AddNode(Node *parentNode, Node &nodeToAdd)
    {           
        if (nodeToAdd._value < parentNode->_value)
        {
            if (parentNode->_left == nullptr)
            {
                parentNode->_left = &nodeToAdd;
            }
            else
            {
                AddNode(parentNode->_left, nodeToAdd);
            }
        }
        else if (nodeToAdd._value > parentNode->_value)
        {
            if (parentNode->_right == nullptr)
            {
                parentNode->_right = &nodeToAdd;
            }
            else
            {
                AddNode(parentNode->_right, nodeToAdd);
            }
        }
        else
        {
            assert(false);
        }
    }
};

The error I get:

Severity    Code    Description Project File    Line    Suppression State
Error   C2893   Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'    BinaryTree  c:\program files (x86)\microsoft visual studio 14.0\vc\include\type_traits  1468    

What am I doing wrong?

omegasbk
  • 738
  • 1
  • 8
  • 23
  • 2
    Instead of the `bind` call and the call to `AddNodeAsync`, it could all be done with a single [lambda expression](http://en.cppreference.com/w/cpp/language/lambda). – Some programmer dude Sep 18 '16 at 10:27
  • replacing those two statements with: auto ftr = async(launch::async, [&]() { AddNodeAsync(root, *this); }); did the trick! But why the first version did not work? – omegasbk Sep 18 '16 at 10:30

3 Answers3

1

look at void AddNodeAsync(Node *parentNode, Node &nodeToAdd) , it takes two arguments, and it is also a member function, should it should get this to bind on. now take a look at your bind:

auto func = bind(&Node::AddNodeAsync, root, ref(*this));

So, bind takes the first and second arguments (the first being a member function , the second is the this to bind on), and binds them together, it is as you where to write

root->AddNodeAsync(ref(*this));

as you can see, you are missing a parameter. for example, this program compiles well:

auto func = bind(&Node::AddNodeAsync, root, root, *this);
David Haim
  • 23,138
  • 3
  • 38
  • 70
1

You forgot the this parameter:

auto func = bind(&Node::AddNodeAsync,this, root, ref(*this));
auto ftr = async(launch::async, func);

Anyway, you could do in one line using a lambda expression:

auto ftr = async(launch::async, [this]{ this->AddNodeAsync(root,*this); }); 
amchacon
  • 1,746
  • 14
  • 25
1

On which Node do you want to call AddNodeAsync? *this? or root? That's exactly the problem: you don't have an instance to call AddNodeAsync on!

You want to specify which instance as first parameter of AddNodeAsync (it's implicit):

auto func = bind(&Node::AddNodeAsync, this, root, *this);
                                      ^^^^
                                   instance to call AddNodeAsync on

Also, it is better to use lambdas instead of std::bind

Community
  • 1
  • 1
Rakete1111
  • 42,521
  • 11
  • 108
  • 141