Reputation: 95
I'm doing a parsing function in C++, which takes a string and a double as arguments and returns the "value" of the string.
Here's the code :
double evaluate (char * toParse, int length, double x)
{
// Case 'x'
if ((toParse[0] == 'x') &&
(length == 1))
{
return x;
}
// Case value
char * endptr;
double num = strtod(toParse, &endptr);
if(endptr - toParse == length)
{
return num;
}
// Parsing
int nBrackets = 0;
for (int i = 0; i < length; i++)
{
if (toParse[i] == '(')
{
nBrackets++;
}
else if (toParse[i] == ')')
{
nBrackets--;
}
// Remove brackets.
double _x = (toParse[0] == '(' && toParse[i-1] == ')' ) ?
evaluate(&toParse[1], i-2, x) : evaluate(toParse, i, x);
double _y = (toParse[i+1] == '(' && toParse[length-1] == ')' ) ?
evaluate(&toParse[i+2], length - (i+1) - 2, x) : evaluate (&toParse[i+1] , length - (i+1), x);
// Supports +, -, * and /
if (nBrackets == 0 &&
toParse[i] == '+')
{
return _x + _y;
}
else if (nBrackets == 0 &&
toParse[i] == '-')
{
return _x - _y;
}
else if (nBrackets == 0 &&
toParse[i] == '*')
{
return _x * _y;
}
else if (nBrackets == 0 &&
toParse[i] == '/')
{
return _x / _y;
}
}
return 0.;
}
int main()
{
cout << evaluate("((4*x)+7)-x", 11, 5.) << endl;
// Outputs 22, which sounds correct.
return 0;
}
It's far from being flawless (no priority on operators, doesn't work if the string contains too much brackets, etc.), but I want to remove the double x argument, and to work on functions directly. (because I want to plot the function, and if I don't work on functions, I will have to parse the same string for each value of x...)
Is it possible ? I mean, doing something like :
double (double) operator+ (double f(double), double g(double))
{
double h (double x)
{
return f(x)+g(x);
}
return h;
}
But it doesn't work, of course. Any ideas ? (class, etc.)
Thanks.
Upvotes: 1
Views: 223
Reputation: 10001
A lambda comes to mind. Unfortunately I believe it would be undefined behavior to return a lambda from a function that captures function arguments. You cannot overload build in types like function pointers either. You could do something like this:
#include <iostream>
#include <functional>
struct CombinedFunction{
enum class Operator{ add, subtract, multiply, divide } op;
CombinedFunction(std::function<double(double)> f1, std::function<double(double)> f2, Operator op) : f1(std::move(f1)), f2(std::move(f2)), op(op){
}
std::function<double(double)> f1, f2;
double operator()(double d){
switch (op){
case Operator::add:
return f1(d) + f2(d);
break;
case Operator::subtract:
//...
break;
//...
}
}
};
std::function<double(double)> operator+ (std::function<double(double)> f, std::function<double(double)> g){
return CombinedFunction(f, g, CombinedFunction::Operator::add);
}
double f(double x){
return 2 * x;
}
double g(double x){
return 3 * x;
}
int main(){
auto h = std::function<double(double)>(f) + g;
std::cout << h(2);
auto h2 = f + h + g;
std::cout << h2(2);
}
It doesn't scale well and it is not very efficient. Maybe there is a template solution that does all this at compile time.
Upvotes: 1
Reputation: 16724
You can use function pointers for that. I didn't understand well if you want a function-pointer as arguments too but here's how you can do that:
typedef double (*handler) (double);
double add(handler x, handler y);
double sub(handler x, handler y);
double func1(double n);
double func2(double n);
int main()
{
double (*funcPtr[256]) (double);
funcPtr['+'] = func1;
funcPtr['-'] = func2;
double answer = funcPtr['+'](2));
}
double func1(double n)
{
return n;
}
double func2(double n)
{
return n;
}
double add(handler x, handler y)
{
return x(2) + y(2);
}
double sub(handler x, handler y)
{
return x(4) - y(2);
}
If it isn't what you're looking for but something like below code let me know and I will edit my answer:
funcPtr[toParse[i]](2, 2); // toParse[i] is '+' it will then call add(2,2)
the 256-size funcPtr
array is with respect to sizeof(char)
. You should make sure index
is an actual value in the array or you will access out of bounds.
Upvotes: 2