I wrote a C++ class that parses expressions like "2 * SQRT(5) + 1". I've created a class called c_function
that "represents" the usual mathematical functions like sqrt
, sin
, cos
etc. something like as follows:
class c_function {
std::string name;
double (*function)(double);
public:
c_function(std::string fname, double (*ffunction)(double)) {
name = fname;
function = ffunction;
}
// ...
};
Then I have a different class that contains a std::vector
of these c_function
objects:
class expression {
std::vector<c_function> functions;
// etc...
public:
// ctor:
expression(/* ... */) {
// ...
functions.push_back(c_function("SQRT", sqrt));
functions.push_back(c_function("SIN" , sin));
functions.push_back(c_function("COS" , cos));
// ...
}
};
The point is that all these functions have one argument. That is fine for most cases but I want to enable adding custom functions to the expression
class and also want to support custom functions with more that one argument (for example, to define a function AREA(a, b)
that returns the product of the two values a and b).
I did that by adding an argument counter argumentCount
and more function "properties" to the c_function
class:
class c_function {
std::string name;
unsigned int argumentCount;
double (*function1)(double);
double (*function2)(double, double);
// ...
};
and used two constructors:
c_function(std::string fname, double (*ffunction)(double)) {
name = fname;
argumentCount = 1;
function1 = ffunction;
function2 = NULL;
};
c_function(std::string fname, double (*ffunction)(double, double)) {
name = fname;
argumentCount = 2;
function1 = NULL;
function2 = ffunction;
};
and added the methods to the expression
class:
// add custom function with one argument
void addFunction(std::string fname, double (*ffunction)(double));
// add custom function with two arguments
void addFunction(std::string fname, double (*ffunction)(double, double));
so that one can define
double Expression_Area(double width, double height) {
return (width * height);
}
and introduce it to the expression
class with
myExpression.addFunction("AREA", Expression_Area);
That works fine and this way I can also add more function "properties" and functions constructors allowing any number of arguments, but
- there is always a limit of the number of arguments that is supported
- the code becomes ugly by having multiple constructors, methods to add a function, and code within the interpretation of the expression just because the number of arguments may be different.
I wonder if there is a way to support functions with any number of arguments more general. I tried changing the c_function
class to:
class c_function {
std::string name;
unsigned int argumentCount;
double (*function)(...);
// ...
};
but this does not work because functions with fixed number of arguments are not accepted by (...)
.
Is there any way to get this solved with one constructor, one function "property" etc.?
C++11 onwards
In C++11 you can use a variadic template to declare a class that will take a function with a variable number of arguments:
You can tweak this basic solution as to how you need your classes to work.
C++98
Pre C++11, you will probably be forced to create classes that take functions with a different number of arguments, so your classes would look something like this:
There's a bit of code duplication here, but it's not too bad.
Remarks
Finally, (although I did not show it above because I think it goes without saying) wherever there is code duplication, template the types so that you can reduce this as much as possible. So, for example, you might consider modifying the C++11
Foo
class above to: