Is there an elegant way to traverse Clang AST Statements? - c++

I am trying to traverse all function definitions and extract information from them. I have to iterate over all statements in the function body, and depending on the type, execute a specific function.
For the moment I have an ugly if-else block. Is there a more elegant way to do this?
void FunctionMatcher::processStatement(const clang::Stmt *statement) {
string type = statement->getStmtClassName();
if (type == "ReturnStmt") {
auto rs = dyn_cast<const ReturnStmt *>(statement);
processReturnStmt(rs);
} else if (type == "WhileStmt") {
auto ws = dyn_cast<WhileStmt>(statement);
processWhileStmt(ws);
} else if (type == "ForStmt") {
auto fs = dyn_cast<const ForStmt *>(statement);
processForStmt(fs);
} else if (type == "IfStmt") {
auto is = dyn_cast<const IfStmt *>(statement);
processIfStmt(is);
} else if (type == "SwitchStmt") {
auto ss = dyn_cast<const SwitchStmt *>(statement);
processSwitchStmt(ss);
} else if (type == "CompoundStmt") {
auto cs = dyn_cast<const CompoundStmt *>(statement);
for (auto child : cs->children())
processStatement(child);
} else {
// ...
}

By navigating through the code of clang::TextNodeDumper, I found a solution.
Apparently Clang has its own visitors for statements, declarations etc...
Simple example:
class StatementVisitor : public ConstStmtVisitor<StatementVisitor> {
public:
StatementVisitor();
void Visit(const Stmt *Node) {
ConstStmtVisitor<StatementVisitor>::Visit(Node);
}
void VisitIfStmt(const IfStmt *Node) {
llvm::outs() << " An if statement yay!\n";
}
void VisitWhileStmt(const WhileStmt *Node) {
llvm::outs() << " A While statement yay!\n";
}
};

you can use RecursiveASTVisitor
its traverse all statement in given code, recursively
class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor>
{
public:
bool VisitFunctionDecl(FunctionDecl* f)
{
...
}
bool VisitIfStmt(IfStmt* IF)
{
...
}
bool VisitForStmt(ForStmt* FS)
{
...
}
bool VisitWhileStmt(WhileStmt* WS)
{
...
}
}

Related

Maximum Sort of a Simple One-way List

I'm trying to do the Maximum Sort of a Simple One-way List. However my program has some bugs in it, which I can't figure out what it is.
It behaves strange because sometimes it works well to a point where it just stop working but i see return 0 (for example: I give the list of 1234 and I get back 3412), sometimes it working to a point, then goes to an infinte loop. (for example: case of 12345 it put 5, 4 and 3 the the 1st place and then infinite loop).
The problem is probably in the list::remMax() or in the maxRend().
My code:
struct chain
{
char key;
chain *next;
};
/////////////////////////////////////////////
class list
{
private:
chain *L, **act;
public:
list() {
L=NULL;
act=&L;
}
~list() {
chain *p;
while(L) {
p=L;
L=L->next;
delete []p;
}
}
enum ERROR {endErr, memErr};
void first() {act=&L;};
void next() {
if(*act!=NULL) {
act=&(*act)->next;
} else throw endErr;
}
bool end() {return *act==NULL;}
bool oneEIn() {return L->next==NULL;} //list contains only 1 element
bool twoEIn() {return L->next->next==NULL;} //list contains 2 elements
void addE(char x) {
chain *p=new(nothrow) chain;
if(p == NULL) throw memErr;
p->key=x;
p->next=*act;
*act=p;
}
chain* remMax(chain *H) {
if(!oneEIn()) {
chain *qe, *q, *Mpe, *Mp;
if(twoEIn()) {
Mp = H;
q = Mp->next;
if(q->key > Mp->key) {
Mp->next=q->next;
return q;
} else {
H=q;
Mp->next=NULL;
return Mp;
}
} else {
Mp=H;
q=Mp->next;
Mpe = H;
qe = Mp;
while(q != NULL) {
if(Mpe->key > Mp->key) Mp = Mpe;
if(q->key > Mp->key) {
Mp=q;
Mpe=qe;
}
qe=q;
q=q->next;
}
if(Mpe == Mp) H=Mp->next;
else {
Mpe->next = Mp->next;
}
Mp->next=NULL;
return Mp;
}
} else {
chain *Mp;
Mp = H;
H = NULL;
return Mp;
}
}
void inE(chain *Mp) {
first();
Mp->next = *act;
addE(Mp->key);
}
chain* getFirst() {return L;}
void printList() {
chain *p=L;
while(p != NULL) {
putchar(p->key);
p=p->next;
}
}
};
///////////////////////////////////
void makeList(list& L) {
char c;
while((c=getchar())!='\n') {
L.addE(c);
L.next();
}
}
void maxRend(list& L) {
if(!L.oneEIn()) {
chain *H, *Mp;
H=L.getFirst();
while(H != NULL) {
cout<<"1.while\n";
Mp = L.remMax(H);
L.inE(Mp);
cout<<"putIn: "<<Mp->key<<endl;
H=H->next;
L.printList();
cout<<endl;
}
cout<<"\nSorted list: ";
L.printList();
} else L.printList();
}
//////////////////////////////////////////////
int main()
{
list L;
makeList(L);
maxRend(L);
return 0;
}

How to avoid copy and paste when two functions are very similar?

I often come across methods that have the same structure and logic, but with some differences and I don't find a proper way not to repeat myself.
For example :
void ChannelSelection::selectAlmostOkChannels(int currentInkId)
{
bool selected = true;
foreach (auto report, m_reports) {
if (report.scoreByInk.find(currentInkId) != report.scoreByInk.end()) {
auto tmpStatus = Assessment::getStatusFromScore(report.scoreByInk.value(currentInkId));
if (tmpStatus == Assessment::Ok)
selected = false;
else if (tmpStatus == Assessment::NotOk)
m_autoSelection[report.name].setSelected(currentInkId, false);
}
}
m_currentSelection.insert(currentInkId, selected);
}
void ChannelSelection::selectNotOkChannels(int currentInkId)
{
bool selected = true;
foreach (auto report, m_reports) {
if (report.scoreByInk.find(currentInkId) != report.scoreByInk.end()) {
auto tmpStatus = Assessment::getStatusFromScore(report.scoreByInk.value(currentInkId));
if (tmpStatus == Assessment::Ok || tmpStatus == Assessment::AlmostOk)
selected = false;
}
}
m_currentSelection.insert(currentInkId, selected);
}
As you can see, these 2 functions are very similar (only the inner if differs). How could I nicely remove duplication in this code?
One of the solution I thought of is using a functor, something like :
void ChannelSelection::selectChannels(int currentInkId, std::function<bool()> fn)
{
bool selected = true;
foreach (auto report, m_reports) {
if (report.scoreByInk.find(currentInkId) != report.scoreByInk.end()) {
auto tmpStatus = Assessment::getStatusFromScore(report.scoreByInk.value(currentInkId));
selected = fn();
}
}
m_currentSelection.insert(currentInkId, selected);
}
The caller gets the responsibility to implement the functor. Is there an alternative without that problem?
You don't have to make your parameterized selectChannels public. It can be a private implementation detail of both selectAlmostOkChannels and selectNotOkChannels, your public functions.
selectChannels can even be implemented as a function template, so that the generated code is equivalent to the hand-written "copy pasted" version, without the maintenance burden of code duplication
template<typename SelectFunction>
void ChannelSelection::selectChannels(int currentInkId, SelectFunction selectFn)
{
bool selected = true;
foreach (auto report, m_reports) {
if (report.scoreByInk.find(currentInkId) != report.scoreByInk.end()) {
auto tmpStatus = Assessment::getStatusFromScore(report.scoreByInk.value(currentInkId));
selected = selectFn(tmpStatus);
/* fill in */
}
}
m_currentSelection.insert(currentInkId, selected);
}
void ChannelSelection::selectAlmostOkChannels(int currentInkId)
{
selectChannels(currentInkId, [] (auto tmpStatus) -> bool {
return /* fill in */;
});
}
void ChannelSelection::selectNotOkChannels(int currentInkId)
{
selectChannels(currentInkId, [] (auto tmpStatus) -> bool {
return /* fill in */;
});
}
You might have been taught that templates need to be in headers, but that's actually not the full story! Template definitions need to be visible where instantiated. Since your template is only used in the private implementation of your member functions, then your template definition can be in the same file that's implementing both your member functions
You might merge two functions into a single one with additional conditional parameter like:
void ChannelSelection::selectChannels(int currentInkId, bool condition)
{
bool selected = true;
foreach (auto report, m_reports) {
if (report.scoreByInk.find(currentInkId) != report.scoreByInk.end()) {
auto tmpStatus = Assessment::getStatusFromScore(report.scoreByInk.value(currentInkId));
if (condition) {
if (tmpStatus == Assessment::Ok) {
selected = false;
} else if (tmpStatus == Assessment::NotOk) {
m_autoSelection[report.name].setSelected(currentInkId, false);
}
} else if (tmpStatus == Assessment::Ok || tmpStatus == Assessment::AlmostOk) {
selected = false;
}
}
}
m_currentSelection.insert(currentInkId, selected);
}
Calling it with condition == true will invoke the equivalent of selectAlmostOkChannels() function, and selectNotOkChannels() otherwise.

How to update a variable that comes from a getter

I need my front method to be able to support doing something like this for my assignment. Its been 4 hours. I can't seem to figure it out. I've tried overloading the = operator but that doesn't seem to work.
vectD3.front() = '{';
vectD3.back() = '}';
basically I need that code to not throw an error when ran
here is my front and back methods
public:T front()
{
if(currentSize > 0)
{
return array[0];
}
else
{
throw std::runtime_error("dynarray has no members");
}
}
public:T back()
{
if(currentSize > 0)
{
return array[currentSize-1];
}
else
{
throw std::runtime_error("dynarray has no members");
}
}
Thanks is advance
You need to return reference by your getter function. then you can modify it.
Something like this :
class A
{
public:
A(char d1): data(d1) {}
char& getData()
{
return data;
}
private:
char data;
};
int main()
{
A a('a');
std::cout << a.getData();//data = a
a.getData() = 'b';
std::cout << a.getData();//data = b
return 0;
}

How Do I Evaluate A User-Defined Expression 44100 Times Per Second

I am working on a VST plugin using C++. The plugin will allow the user to enter a math expression, which will then be run 44100 times per second in order to generate sound. I am new to realtime stuff like this, as well as interpreting user entered expressions.
The issue is that I cannot find a method to evaluate a user defined function that can run that fast. My best attempt has been to convert the user entered expression into RPN when it's entered, and then having a function evaluate the RPN expression to generate the audio. I implemented the RPN evaluation function and hard-coded an RPN expression to test it. While it seems to evaluate correctly, it does not seem to be doing it fast enough.
Here is my evaluation function, in addition to a couple RPN expressions:
#include <string>
#include <stack>
#include <deque>
/*
* an RPN expression is stored as a deque of strings
*
* each string is either an operator, a number, or the single variable t
*
* the deque is read from front to back
*/
std::deque<std::string> simpleCase, complexCase;
//simple expression, just the variable t
simpleCase.push_back("t");
//more complex expression, t*(42&(t>>11))
complexCase.push_back("t");
complexCase.push_back("42");
complexCase.push_back("t");
complexCase.push_back("11");
complexCase.push_back(">>");
complexCase.push_back("&");
complexCase.push_back("*");
/*
* The evalRPN function takes an RPN deque, plugs in a supplied t,
* and evaluates it.
*
* The idea is that t increases continually, and that the integer overflow
* causes the output to oscillate between 0 and 255.
*
* t is a double, but I convert it to a uint32_t.
*
* Allowed operators: bitwise logic (&, |, ^), bitshifts (<<, >>),
* and math (+, -, *, /, %)
*
* Allowed vars: t
*
* Supplied numbers are converted from string to char arrays then to an int
*
* This also assumes the RPN is not ill-formatted.
*/
uint8_t evalRPN(std::deque<std::string> rpnExpr, double tVal)
{
std::stack<uint8_t> numberStack;
std::string token;
while(rpnExpr.size() > 0)
{
token = rpnExpr.front();
rpnExpr.pop_front();
if(token.find_first_not_of("0123456789") == std::string::npos)
{
//if token is a number
numberStack.push((uint8_t)atoi(token.c_str()));
}
else if (token == "t")
{
numberStack.push((uint8_t)tVal);
}
else
{
uint8_t last = numberStack.top();
numberStack.pop();
uint8_t first = numberStack.top();
numberStack.pop();
if(token == "^")
{
numberStack.push(first ^ last);
}
else if (token == "&")
{
numberStack.push(first & last);
}
else if (token == "|")
{
numberStack.push(first | last);
}
else if (token == "<<")
{
numberStack.push(first >> last);
}
else if (token == ">>")
{
numberStack.push(first >> last);
}
else if (token == "+")
{
numberStack.push(first + last);
}
else if (token == "-")
{
numberStack.push(first - last);
}
else if (token == "*")
{
numberStack.push(first * last);
}
else if (token == "/")
{
numberStack.push(first / last);
}
else if (token == "%")
{
numberStack.push(first % last);
}
}
}
//assume one left in numberStack
return(numberStack.top());
}
Are there any optimizations I can make in my RPN processing to make it potentially run fast enough? Alternatively is there another way of handling the RPN computation that's more efficient?
Additionally, is there another method that's C++ compatible for taking a user entered string representing a standard math expression, and then running that expression fast enough to be completed in under 1/44100th of a second?
This is a great question.
Compiling your expression into RPN is a good start, and in fact it kinda looks to me like your code should probably be able to execute more than 88K expressions per second, unless they are quite long.
BUT, you can certainly do a lot better without too much trouble.
I would make an interface like this:
class Expression
{
public:
virtual uint32_t eval(uint32_t tVal) = 0;
};
You will then compile your expression into an implementation of this interface.
You can have an implementation for constants:
class ConstExpression : public Expression
{
private:
uint32_t m_constVal;
public:
// ...
uint32_t eval(uint32_t tVal)
{
return m_constVal;
}
};
...an implementation for a reference to t
class RefExpression : public Expression
{
public:
// ...
uint32_t eval(uint32_t tVal)
{
return m_tVal;
}
};
... and implementations for the binary operators
class AddExpression : public Expression
{
private:
auto_ptr<Expression> m_left;
auto_ptr<Expression> m_right;
public:
// ...
uint32_t eval(uint32_t tVal)
{
return m_left->eval(tVal) + m_right->eval(tVal);
}
};
... maybe you want to do some template magic to avoid having to hand code so many operator classes.
Anyway, after compiling your expression into an Expression, you can evaluate it simply like theExpression->eval(t), and all the code executes in a reasonably efficient manner with no parsing, string compares, stack manipulation, etc.
How about realtime generating code, compile it and then use as binary library function? I'm sure it will work much more faster.
You don't have to. If you are building a vst, you have to use the vst libraries. The host daw will call the update functions automatically.
Thanks for all your advice! I have since implemented a solution I am immensely happy with. While none of the answers here directly informed me of this approach, they did inspire me.
I decided to parse the user-input infix expressions into polish notation (prefix), and then into binary trees. I implemented a TreeNode struct specifically for this, which is essentially a doubly linked list, but with 2 children instead of 1. Each TreeNode can either be set as a variable, a fixed number, or an operator. If it's set as an operator, it's opFunc function pointer member is set to a predefined function that performs that operator.
Each node has an evaluate(tVal) member function. If it's a fixed number, this just returns that number. If it's a variable, it just returns tVal. If it's an operator, it returns opFunc(first->evaluate(tVal), last->evaluate(tVal)), which recursively calculates the two nodes beneath it, then performs the it's operator on them.
I also implemented an ExpressionTree class which manages the tree and parses user input into a tree. It has public members for destroying the tree recursively, building the tree from a user input string, and evaluating the tree (it just needs to evaluate the root node).
Because this uses function pointers in a simple recursive tree, it's astoundingly fast to evaluate an ExpressionTree, even when the formulas get very large. Essentially, I have moved more or less as much processing as possible away from when the function is being evaluated and to when the formula is entered.
Below is the code I wrote for the expression trees. Note that only very limited operators exist, however it is easy to add new binary operators by including them in the precedence map, adding a function for them, and including a switch in setOp. There is also only one variable allowed, which is all my application will use.
There is also no error checking implemented at the moment, so invalid operators, spaces, or mismatched parentheses will result in undefined behavior ATM.
Also note that the expressions are processed as uint32_t and turned into a uint8_t at the end, as that's what my application calls for. When I'm done with this project, I may generalize this as a library and publish it.
TreeExpressions.hpp:
#include <cstdint>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <algorithm>
struct TreeNode {
private:
bool isOp = false;
bool isVar = false;
uint32_t value = 0;
uint32_t(*opFunc)(uint32_t, uint32_t) = NULL;
static inline uint32_t xorOp(uint32_t a, uint32_t b) { return(a ^ b); };
static inline uint32_t andOp(uint32_t a, uint32_t b) { return(a & b); };
static inline uint32_t orOp(uint32_t a, uint32_t b) { return(a | b); };
static inline uint32_t lshiftOp(uint32_t a, uint32_t b) { return(a << b); };
static inline uint32_t rshiftOp(uint32_t a, uint32_t b) { return(a >> b); };
static inline uint32_t addOp(uint32_t a, uint32_t b) { return(a + b); };
static inline uint32_t subOp(uint32_t a, uint32_t b) { return(a - b); };
static inline uint32_t multOp(uint32_t a, uint32_t b) { return(a * b); };
static inline uint32_t divOp(uint32_t a, uint32_t b) { return(a / b); };
static inline uint32_t modOp(uint32_t a, uint32_t b) { return(a % b); };
public:
TreeNode *first = NULL;
TreeNode *last = NULL;
TreeNode *parent = NULL;
uint32_t evaluate(uint32_t tVal);
void setOp(std::string op);
void setVal(uint32_t val);
void setVar();
};
class ExpressionTree
{
private:
std::map<std::string, int> precedence;
TreeNode *treeRoot;
TreeNode *insertNode(TreeNode *leaf);
void destroyTree(TreeNode *leaf);
public:
ExpressionTree();
~ExpressionTree();
void destroyTree();
bool build(std::string formulaStr);
uint8_t evaluate(uint32_t tVal);
};
TreeExpressions.cpp:
#include "TreeExpressions.h"
void TreeNode::setOp(std::string op)
{
isVar = false;
isOp = true;
if (op == "^")
{
opFunc = &xorOp;
}
else if (op == "&")
{
opFunc = &andOp;
}
else if (op == "|")
{
opFunc = &orOp;
}
else if (op == "<<")
{
opFunc = &lshiftOp;
}
else if (op == ">>")
{
opFunc = &rshiftOp;
}
else if (op == "+")
{
opFunc = &addOp;
}
else if (op == "-")
{
opFunc = &subOp;
}
else if (op == "*")
{
opFunc = &multOp;
}
else if (op == "/")
{
opFunc = &divOp;
}
else if (op == "%")
{
opFunc = &modOp;
}
}
void TreeNode::setVal(uint32_t val)
{
isVar = false;
isOp = false;
value = val;
}
void TreeNode::setVar()
{
isVar = true;
isOp = false;
}
uint32_t TreeNode::evaluate(uint32_t tVal)
{
if (isOp)
{
//if it's an op
return( opFunc( first->evaluate(tVal), last->evaluate(tVal) ) );
}
else if (isVar)
{
//if it's a var
return(tVal);
}
else
{
//if it's a number
return(value);
}
}
ExpressionTree::ExpressionTree()
{
treeRoot = NULL;
// http://en.cppreference.com/w/cpp/language/operator_precedence
precedence["*"] = 5;
precedence["/"] = 5;
precedence["%"] = 5;
precedence["+"] = 6;
precedence["-"] = 6;
precedence["<<"] = 7;
precedence[">>"] = 7;
precedence["&"] = 10;
precedence["^"] = 11;
precedence["|"] = 12;
}
ExpressionTree::~ExpressionTree()
{
destroyTree();
}
void ExpressionTree::destroyTree(TreeNode *leaf)
{
if (leaf != NULL)
{
destroyTree(leaf->first);
destroyTree(leaf->last);
delete leaf;
}
}
TreeNode *ExpressionTree::insertNode(TreeNode *leaf)
{
if (leaf->first == NULL)
{
leaf->first = new TreeNode;
leaf->first->parent = leaf;
return(leaf->first);
}
else
{
leaf->last = new TreeNode;
leaf->last->parent = leaf;
return(leaf->last);
}
}
void ExpressionTree::destroyTree()
{
destroyTree(treeRoot);
}
bool ExpressionTree::build(std::string formulaStr)
{
std::string::iterator stringIterator;
std::vector<std::string>::iterator stringVectorIterator;
std::vector<std::string> formulaTokens;
std::vector<std::string> pnTokens;
std::stack<std::string> stringStack;
std::string currentNumString = "";
std::string currentTokenString = "";
std::stack<TreeNode> nodeStack;
TreeNode *currentNode;
std::string currToken;
bool treeIsDone;
//tokenization
for (stringIterator = formulaStr.begin(); stringIterator != formulaStr.end(); stringIterator++)
{
std::string currCharString(1, *stringIterator);
currentTokenString.push_back(*stringIterator);
if ((precedence.find(currentTokenString) != precedence.end()) || (currentTokenString == "(") || (currentTokenString == ")"))
{
//if the current token string is found in the precedence list (or is a parentheses)
if (currentNumString != "")
{
formulaTokens.push_back(currentNumString);
currentNumString = "";
}
formulaTokens.push_back(currentTokenString);
currentTokenString = "";
}
else if (std::all_of(currentTokenString.begin(), currentTokenString.end(), ::isdigit))
{
//if the current token string is all digits
currentNumString.append(currentTokenString);
currentTokenString = "";
}
else if (currentTokenString == "t")
{
//if the current token string is the t variable
formulaTokens.push_back(currentTokenString);
currentTokenString = "";
}
}
//convert to polish notation
std::reverse(formulaTokens.begin(), formulaTokens.end());
stringStack.push(")");
for (stringVectorIterator = formulaTokens.begin(); stringVectorIterator != formulaTokens.end(); stringVectorIterator++)
{
currToken = *stringVectorIterator;
if ((precedence.find(currToken) == precedence.end()) && (currToken != "(") && (currToken != ")"))
{
pnTokens.push_back(currToken);
}
else if (currToken == ")")
{
stringStack.push(currToken);
}
else if (precedence.find(currToken) != precedence.end())
{
if (stringStack.size() > 0)
{
if (stringStack.top() != ")")
{
while (precedence[stringStack.top()] <= precedence[currToken])
{
if (stringStack.top() != ")")
{
pnTokens.push_back(stringStack.top());
stringStack.pop();
}
if (stringStack.size() <= 0)
{
break;
}
if (stringStack.top() == ")")
{
break;
}
}
}
}
stringStack.push(currToken);
}
else if (currToken == "(")
{
if (stringStack.size() > 0)
{
while (stringStack.top() != ")")
{
pnTokens.push_back(stringStack.top());
stringStack.pop();
if (stringStack.size() <= 0)
{
break;
}
}
stringStack.pop();
}
}
}
while (stringStack.size() > 0)
{
if (stringStack.top() != ")")
{
pnTokens.push_back(stringStack.top());
}
stringStack.pop();
}
std::reverse(pnTokens.begin(), pnTokens.end());
//if it's gotten this far, the formula was valid
//destroy the current tree to make room
destroyTree();
//parse polish notation into tree
treeRoot = new TreeNode;
currentNode = treeRoot;
treeIsDone = false;
for (stringVectorIterator = pnTokens.begin(); stringVectorIterator != pnTokens.end(); stringVectorIterator++)
{
currToken = *stringVectorIterator;
if (precedence.find(currToken) != precedence.end())
{
//if the token is an operator
currentNode->setOp(currToken);
currentNode = insertNode(currentNode);
}
else
{
//if it's a number or a variable
if (currentNode->first != NULL)
{
//if the current node has it's first branch initialized
while (currentNode->last != NULL)
{
//while the last branch is initialized
currentNode = currentNode->parent;
}
currentNode = insertNode(currentNode);
}
if (std::all_of(currToken.begin(), currToken.end(), ::isdigit))
{
//if it's a number
currentNode->setVal((uint32_t)atoi(currToken.c_str()));
}
else
{
//if it's something else, a variable
currentNode->setVar();
}
if (currentNode != treeRoot)
{
currentNode = currentNode->parent;
}
//since we just moved up, we know at least the first branch is used
//so only check the last
while (currentNode->last != NULL)
{
//if the last node is not free
if (currentNode == treeRoot)
{
//if we're at the root, and it's totally populated
treeIsDone = true;
break;
}
currentNode = currentNode->parent;
}
if (!treeIsDone)
{
currentNode = insertNode(currentNode);
}
}
}
return(true);
}
uint8_t ExpressionTree::evaluate(uint32_t tVal)
{
return((uint8_t)treeRoot->evaluate(tVal));
}

template class type conversion

I'm learning about templating in C++ and I'm trying to write a template class to handle different data types in order to read a configuration text file formatted in a way similar to
TYPE,DEFAULT_VALUE
I defined the following class
template <class T>
class option_t
{
public:
option_t(std::string _type, std::string _defaultValue);
//~option_t();
std::string get_type();
T get_defaultValue();
private:
T defaultValue;
};
template <class T>
option_t<T>::option_t(std::string _type,std::string _defaultValue)
{
type = _type;
if( type.compare("integer") == 0)
{
defaultValue = std::stoi(_defaultValue);
}
else if(type.compare("real") == 0)
{
char *pEnd;
defaultValue = std::strtod(_defaultValue.c_str(),&pEnd);
}
else if( type.compare("boolean") == 0 )
{
std::transform(_defaultValue.begin(),_defaultValue.end(),_defaultValue.begin(),::tolower);
if(_defaultValue.compare("true") == 0 ||
_defaultValue.compare("1") == 0 ||
_defaultValue.compare("on") == 0)
{
defaultValue = true;
}
else
{
defaultValue = false;
}
}
else
{
//LOG(ERROR) << "Option " << name << " : unknown data type ( " << type << " )";
}
template <class T>
std::string option_t<T>::get_type()
{
return type;
}
template <class T>
T option_t<T>::get_defaultValue()
{
return defaultValue;
}
and when I use the following line into my main code
int tmpInt = option.get_defaultValue();
I get a compilation error "no viable conversion from 'std::__1::basic_string' to 'int'"
What does it mean? And how can I solve it?
Thanks and sorry for the stupid question :-)
Here all rest of my code
class options_t
{
public:
options_t();
//~options_t();
template <class T>
void set_option(option_t<T> option);
private:
};
options_t::options_t()
{
// read file and depending on _type create a specific option object
std::string _type = "integer";
std::string _defaultValue = "5";
if(_type.compare("integer") == 0)
{
option_t<int> option(_type,_defaultValue);
set_option(option);
}
else if(_type.compare("real") == 0)
{
option_t<double> option(_type,_defaultValue);
set_option(option);
}
else if(_type.compare("boolean") == 0)
{
option_t<bool> option(_type,_defaultValue);
set_option(option);
}
else if(_type.compare("string") == 0)
{
option_t<std::string> option(_type,_defaultValue);
set_option(option);
}
else
{
// LOG(ERROR) << " invalid data type( " << _type << " )";
}
}
template <class T>
void options_t::set_option(option_t<T> option)
{
std::string _type = option.get_type();
if(_type.compare("integer") == 0)
{
int tmpInt = option.get_defaultValue();
option_t<int> tmpOption(option.get_type(),defaultValue);
}
else if(_type.compare("real") == 0)
{
//todo;
}
else if(_type.compare("boolean") == 0)
{
//todo;
}
else if(_type.compare("string") == 0)
{
//todo;
}
else
{
// LOG(ERROR) << " invalid data type( " << option.get_type() << " )";
}
}
int main()
{
options_t options();
}
Depends on what you want to do. I will assume that int tmpInt is correct.
To retrieve an int, option has to be option_t<int> or option_t<T> where T is convertible to int. Look likes you're trying to use a string.