Reputation: 29
I get some errors when I try to run the next code:
// tree.cpp
// compile with: g++ -std=c++11 tree.cpp -o tree
#include <iostream>
#include <future>
using namespace std;
int valtab[127]; // used for integer values of variables
class Tree; // forward declare
class Node {
protected:
Node() { use = 1; }
virtual void print(ostream &os) = 0;
virtual ~Node() { }
virtual int eval() = 0;
private:
friend class Tree;
friend ostream& operator<<(ostream&, const Tree&);
int use; // reference count
};
class Tree {
public:
Tree(int n); // constant
Tree(char id); // variable
Tree(char op, Tree t); // unary operator
Tree(char op, Tree left, Tree right); // binary operator
Tree(const Tree &t) { p = t.p; ++p->use; }
~Tree() { if (--p->use == 0) delete p; }
void operator=(const Tree &t);
int eval() { return p->eval(); }
private:
friend class Node;
friend ostream& operator<<(ostream &os, const Tree &t);
Node *p; // polymorphic hierarchy
};
void Tree::operator=(const Tree &t)
{
++t.p->use;
if (--p->use == 0)
delete p;
p = t.p;
}
ostream& operator<<(ostream &os, const Tree &t)
{
t.p->print(os);
return os;
}
class LeafNode: public Node {
private:
friend class Tree;
void print(ostream &os) = 0;
virtual int eval() = 0;
};
class IntNode: public LeafNode {
public:
int eval() { return n; }
private:
friend class Tree;
int n;
void print(ostream &os) { os << n ;}
IntNode(int k): n(k) { }
};
class IdNode: public LeafNode {
public:
int eval() { return valtab[name]; }
private:
friend class Tree;
char name;
void print(ostream& o) { o << name; }
IdNode(char id): name(id) { }
};
class UnaryNode: public Node {
public:
int eval();
private:
friend class Tree;
const char op;
Tree opnd;
UnaryNode(char a, Tree b): op(a), opnd(b) { }
void print(ostream& o) { o << "(" << op << opnd << ")"; }
};
int UnaryNode::eval()
{
switch (op) {
case '-': return (-opnd.eval());
case '+': return (+opnd.eval());
default: cerr << "no operand" << endl;
return 0;
}
}
class BinaryNode: public Node {
public:
int eval();
private:
friend class Tree;
const char op;
Tree left;
Tree right;
BinaryNode(char a, Tree b, Tree c): op(a), left(b), right(c) { }
void print(ostream &os) { os << "(" << left << op << right << ")"; }
};
int BinaryNode::eval()
{
switch (op) {
case '-': {
future<int> left = async(launch::async, left.eval());
future<int> right = async(launch::async, right.eval());
//return (left.get() - right.get());
}
case '+': return (left.eval() + right.eval());
case '*': return (left.eval() * right.eval());
default: cerr << "no operand" << endl;
return 0;
}
}
Tree::Tree(int n) { p = new IntNode(n); }
Tree::Tree(char id) { p = new IdNode(id); }
Tree::Tree(char op, Tree t) { p = new UnaryNode(op, t); }
Tree::Tree(char op, Tree left, Tree right) { p = new BinaryNode(op, left, right); }
int main()
{
valtab['A'] = 3; valtab['B'] = 4;
cout << "A = 3, B = 4" << endl;
Tree t1 = Tree('*', Tree('-', 5), Tree('+', 'A', 4));
Tree t2 = Tree('+', Tree('-', 'A', 1), Tree('+', t1, 'B'));
cout << "t1 = " << t1 << ", t2 = " << t2 << endl;
cout << "t1 = " << t1.eval() << ", t2 = " << t2.eval() << endl;
return 0;
}
This error I received:
error: 'class std::future<int>' has no member named 'eval'
I want to change the program so that expressions are evaluated in a parallel fashion. But I'm stuck with the future implementation, I do not quite understand how it works. Well, I understands how it works but I don't understand why I'm receiving these errors.
I hope some one can give me some tips or point me in the right direction.
Upvotes: 1
Views: 1527
Reputation: 54589
The parameter to std::async
is a function (or more precisely, a Callable).
In particular, you do not invoke the function yourself (which would yield the return value). Invoking is done by std::async
.
So these lines:
future<int> left = async(launch::async, left.eval());
future<int> right = async(launch::async, right.eval());
Should instead read something like:
future<int> left_result = std::async(launch::async, [this]() { return left.eval(); });
future<int> right_result = std::async(launch::async, [this]() { return right.eval(); });
Note that the function call is now wrapped in a lambda. Note also that you also reused the names for left
and right
in your original code, which is more trouble. I renamed them here to make it work.
As usual, since you now have concurrency in your program, you need to care about data races . Currently this seems to be fine, as all nodes in the tree are distinct, so the async calls don't share any data with each other. But keep it in mind for any future changes.
Upvotes: 1
Reputation: 66194
You're trying to invoke a virtual member function as an async, but not properly providing the object to pin it against. Further, your use of same-id local vars, while not directly introducing an error, makes this incredibly hard to read.
I believe this is what you're shooting for:
auto eLeft = std::async(std::launch::async, std::bind(&Tree::eval, &this->left));
auto eRight = std::async(std::launch::async, std::bind(&Tree::eval, &this->right));
return (eLeft.get() - eRight.get());
Though, to be completely honest, this seems overkill. I see no sense in spinning up two asyncs just to then wait on both. Why not spin up one, then use the current thread to perform the other half of of your task:
auto eRight = std::async(std::launch::async, std::bind(&Tree::eval, &this->right));
return (left.eval() - eRight.get());
Upvotes: 1