I have the following function that takes a symbol table and adds a composited function to the symbol table:
void add_function(exprtk::symbol_table<double>& symtab) {
using compositor_t = exprtk::function_compositor<double>;
using function_t = typename compositor_t::function;
compositor_t compositor(symtab);
const bool res = compositor.add(
function_t("incrementor")
.var("x")
.expression
( " x + 1; " ));
if (!res) {
printf("comp err!");
}
}
Later on I call the add function and then compile an expression that uses the sym table
using symbol_table_t = exprtk::symbol_table<double>;
using expression_t = exprtk::expression<double>;
using parser_t = exprtk::parser<double>;
double x = 123.0;
symbol_table_t symbol_table;
expression_t expression;
parser_t parser;
symbol_table.add_variable("x", x);
add_function(symbol_table);
expression.register_symbol_table(symbol_table);
const std::string program = "incrementor(x)";
if (!parser.compile(program,expression)) {
printf("err: %s\n",parser.error().c_str());
return;
}
However the parser.compile
returns false, and I get the following error:
Error: ERR232 - Undefined symbol: 'incrementor'
I've checked the sym table using a debugger and the incrementor function is not there. Not sure why or how the incrementor symbol disappears between the call to add_function and compile.
In the add_function
you correctly pass the symtab during the function_compositor constructor, so that any new composited functions have their references added to the symtab
The main issue you're seeing occurs at the closing brace of the add_function.
At that point the destructors for all the function local defined instances are invoked. This includes the destructor for the function_compositor
instance.
During destruction a protection mechanism within the function_compositor
kicks in and removes all composited function references that have been created from the symbol tables they have been registered with. This is done so that no expressions can be compiled that would be referencing composited functions that no longer exist causing undefined behaviour.
This means that just before the closing brace, using the debugger you would indeed see the reference to the "incrementor" composited function, however just after that it will have been removed.
Subsequently when the expression is compiled, the symbol name "incrementor" will be undefined resulting in the given error diagnostic.
In the ExprTk readme.txt
there is the following note:
The life-time of objects registered with or created from a
specific symbol-table must span at least the lifetime of the
symbol table instance and all compiled expressions which
utilise objects, such as variables, strings, vectors,
function compositor functions and functions of that symbol-
table, otherwise the result will be undefined behaviour.
As a side note, a function_compositor
is fundamentally an object factory - similar to a parser
instance. As such it should only be constructed once during the life-time of the process and destructed only after it will no longer be required. It should not be constructed and destructed on an ad-hoc basis.
My recommendation is to couple both the symbol_table
and function_compositor
instances so that they are destructed at the same point.