C++ Mathematical Expression Library (ExprTk) https://www.partow.net/programming/exprtk/index.html
This commit is contained in:
parent
9cddffaf52
commit
628477bf47
2422
exprtk.hpp
2422
exprtk.hpp
File diff suppressed because it is too large
Load Diff
|
@ -39,14 +39,14 @@ void square_wave()
|
|||
|
||||
static const T pi = T(3.141592653589793238462643383279502);
|
||||
|
||||
T f = pi / T(10);
|
||||
T t = T(0);
|
||||
T a = T(10);
|
||||
const T f = pi / T(10);
|
||||
const T a = T(10);
|
||||
T t = T(0);
|
||||
|
||||
symbol_table_t symbol_table;
|
||||
symbol_table.add_variable("f",f);
|
||||
symbol_table.add_variable("t",t);
|
||||
symbol_table.add_variable("a",a);
|
||||
symbol_table.add_constant("f",f);
|
||||
symbol_table.add_constant("a",a);
|
||||
symbol_table.add_constants();
|
||||
|
||||
expression_t expression;
|
||||
|
|
|
@ -30,9 +30,9 @@ void polynomial()
|
|||
|
||||
std::string expression_string = "25x^5 - 35x^4 - 15x^3 + 40x^2 - 15x + 1";
|
||||
|
||||
T r0 = T(0);
|
||||
T r1 = T(1);
|
||||
T x = T(0);
|
||||
const T r0 = T(0);
|
||||
const T r1 = T(1);
|
||||
T x = T(0);
|
||||
|
||||
symbol_table_t symbol_table;
|
||||
symbol_table.add_variable("x",x);
|
||||
|
|
|
@ -70,7 +70,7 @@ void fibonacci()
|
|||
|
||||
for (std::size_t i = 0; i < 40; ++i)
|
||||
{
|
||||
x = i;
|
||||
x = static_cast<T>(i);
|
||||
|
||||
T result = expression.value();
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ void primes()
|
|||
|
||||
for (std::size_t i = 0; i < 100; ++i)
|
||||
{
|
||||
x = i;
|
||||
x = static_cast<T>(i);
|
||||
|
||||
T result1 = expression1.value();
|
||||
T result2 = expression2.value();
|
||||
|
|
|
@ -72,7 +72,7 @@ void newton_sqrt()
|
|||
|
||||
for (std::size_t i = 0; i < 100; ++i)
|
||||
{
|
||||
x = i;
|
||||
x = static_cast<T>(i);
|
||||
|
||||
T result = expression.value();
|
||||
|
||||
|
|
|
@ -4848,7 +4848,7 @@ inline std::size_t load_expressions(const std::string& file_name,
|
|||
|
||||
std::size_t line_count = 0;
|
||||
|
||||
while (std::getline(stream,buffer))
|
||||
while (std::getline(stream,(buffer)))
|
||||
{
|
||||
if (buffer.empty())
|
||||
continue;
|
||||
|
@ -7685,7 +7685,7 @@ struct my_usr_ext : public exprtk::parser<T>::unknown_symbol_resolver
|
|||
{
|
||||
static T var_default_value = 1.0;
|
||||
|
||||
if (!(result = symbol_table.create_variable(unknown_symbol, var_default_value++)))
|
||||
if ((result = symbol_table.create_variable(unknown_symbol, var_default_value++)) == false)
|
||||
{
|
||||
error_message = "Failed to create variable(" + unknown_symbol + ") in primary symbol table";
|
||||
}
|
||||
|
@ -7694,7 +7694,7 @@ struct my_usr_ext : public exprtk::parser<T>::unknown_symbol_resolver
|
|||
{
|
||||
static T cvar_default_value = 1.0;
|
||||
|
||||
if (!(result = symbol_table.add_constant(unknown_symbol, cvar_default_value++)))
|
||||
if ((result = symbol_table.add_constant(unknown_symbol, cvar_default_value++)) == false)
|
||||
{
|
||||
error_message = "Failed to create const variable(" + unknown_symbol + ") in primary symbol table";
|
||||
}
|
||||
|
|
208
readme.txt
208
readme.txt
|
@ -224,7 +224,7 @@ of C++ compilers:
|
|||
+----------+---------------------------------------------------------+
|
||||
| true | True state or any value other than zero (typically 1). |
|
||||
+----------+---------------------------------------------------------+
|
||||
| false | False state, value of zero. |
|
||||
| false | False state, value of exactly zero. |
|
||||
+----------+---------------------------------------------------------+
|
||||
| and | Logical AND, True only if x and y are both true. |
|
||||
| | (eg: x and y) |
|
||||
|
@ -275,7 +275,7 @@ of C++ compilers:
|
|||
| clamp | Clamp x in range between r0 and r1, where r0 < r1. |
|
||||
| | (eg: clamp(r0,x,r1)) |
|
||||
+----------+---------------------------------------------------------+
|
||||
| equal | Equality test between x and y using normalized epsilon |
|
||||
| equal | Equality test between x and y using normalised epsilon |
|
||||
+----------+---------------------------------------------------------+
|
||||
| erf | Error function of x. (eg: erf(x)) |
|
||||
+----------+---------------------------------------------------------+
|
||||
|
@ -321,7 +321,7 @@ of C++ compilers:
|
|||
+----------+---------------------------------------------------------+
|
||||
| ncdf | Normal cumulative distribution function. (eg: ncdf(x)) |
|
||||
+----------+---------------------------------------------------------+
|
||||
| nequal | Not-equal test between x and y using normalized epsilon |
|
||||
| nequal | Not-equal test between x and y using normalised epsilon |
|
||||
+----------+---------------------------------------------------------+
|
||||
| pow | x to the power of y. (eg: pow(x,y) == x ^ y) |
|
||||
+----------+---------------------------------------------------------+
|
||||
|
@ -499,7 +499,7 @@ of C++ compilers:
|
|||
| | eg: |
|
||||
| | 1. if (x > y) z; else w; |
|
||||
| | 2. if (x > y) z; else if (w != u) v; |
|
||||
| | 3. if (x < y) {z; w + 1;} else u; |
|
||||
| | 3. if (x < y) { z; w + 1; } else u; |
|
||||
| | 4. if ((x != y) and (z > w)) |
|
||||
| | { |
|
||||
| | y := sin(x) / u; |
|
||||
|
@ -651,7 +651,7 @@ expressions. The types are as follows:
|
|||
|
||||
(1) Scalar Type
|
||||
The scalar type is a singular numeric value. The underlying type is
|
||||
that used to specialize the ExprTk components (float, double, long
|
||||
that used to specialise the ExprTk components (float, double, long
|
||||
double, MPFR et al).
|
||||
|
||||
|
||||
|
@ -673,7 +673,7 @@ however can not interact with scalar or vector types.
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
[SECTION 10 - COMPONENTS]
|
||||
There are three primary components, that are specialized upon a given
|
||||
There are three primary components, that are specialised upon a given
|
||||
numeric type, which make up the core of ExprTk. The components are as
|
||||
follows:
|
||||
|
||||
|
@ -791,8 +791,9 @@ methods:
|
|||
4. bool add_vector (const std::string& name, vector_type&)
|
||||
|
||||
|
||||
The 'vector' type must consist of a contiguous array of scalars which
|
||||
can be one of the following:
|
||||
Note: The 'vector' type must be comprised from a contiguous array of
|
||||
scalars with a size that is larger than zero. The vector type itself
|
||||
can be any one of the following:
|
||||
|
||||
1. std::vector<scalar_t>
|
||||
2. scalar_t(&v)[N]
|
||||
|
@ -800,6 +801,18 @@ can be one of the following:
|
|||
4. exprtk::vector_view<scalar_t>
|
||||
|
||||
|
||||
When registering a variable, vector, string or function with an
|
||||
instance of a symbol_table, the call to 'add_...' may fail and return
|
||||
a false result due to one or more of the following reasons:
|
||||
|
||||
1. Variable name contains invalid characters or is ill-formed
|
||||
2. Variable name conflicts with a reserved word (eg: 'while')
|
||||
3. Variable name conflicts with a previously registered variable
|
||||
4. A vector of size (length) zero is being registered
|
||||
5. A free function exceeding fifteen parameters is being registered
|
||||
6. The symbol_table instance is in an invalid state
|
||||
|
||||
|
||||
(2) Expression
|
||||
A structure that holds an abstract syntax tree or AST for a specified
|
||||
expression and is used to evaluate said expression. Evaluation of the
|
||||
|
@ -920,8 +933,8 @@ including which control block each expression references and their
|
|||
associated reference counts.
|
||||
|
||||
|
||||
exprtk::expression e0; // constructed expression, eg: x + 1
|
||||
exprtk::expression e1; // constructed expression, eg: 2z + y
|
||||
exprtk::expression e0; // constructed expression, eg: x + 1
|
||||
exprtk::expression e1; // constructed expression, eg: 2z + y
|
||||
|
||||
+-----[ e0 cntrl block]----+ +-----[ e1 cntrl block]-----+
|
||||
| 1. Expression Node 'x+1' | | 1. Expression Node '2z+y' |
|
||||
|
@ -934,7 +947,7 @@ associated reference counts.
|
|||
+--------------------+ +--------------------+
|
||||
|
||||
|
||||
e0 = e1; // e0 and e1 are now 2z+y
|
||||
e0 = e1; // e0 and e1 are now 2z+y
|
||||
|
||||
+-----[ e1 cntrl block]-----+
|
||||
| 1. Expression Node '2z+y' |
|
||||
|
@ -1226,7 +1239,7 @@ In the following example, the return value of the expression will be
|
|||
within the loop body on its last iteration:
|
||||
|
||||
var x := 1;
|
||||
x + for (var i := i; i < 10; i += 1)
|
||||
x + for (var i := x; i < 10; i += 1)
|
||||
{
|
||||
i / 2;
|
||||
i + 1;
|
||||
|
@ -1303,7 +1316,7 @@ lets review the following expression:
|
|||
|
||||
var x := 2; // Statement 1
|
||||
var y := x + 2; // Statement 2
|
||||
x + y // Statement 3
|
||||
x + y; // Statement 3
|
||||
y := x + 3y; // Statement 4
|
||||
x - y; // Statement 5
|
||||
|
||||
|
@ -1332,9 +1345,9 @@ ExprTk support two forms of conditional branching or otherwise known
|
|||
as if-statements. The first form, is a simple function based
|
||||
conditional statement, that takes exactly three input expressions:
|
||||
condition, consequent and alternative. The following is an example
|
||||
expression that utilizes the function based if-statement.
|
||||
expression that utilises the function based if-statement.
|
||||
|
||||
x := if (y < z, y + 1, 2* z)
|
||||
x := if (y < z, y + 1, 2 * z)
|
||||
|
||||
|
||||
In the example above, if the condition 'y < z' is true, then the
|
||||
|
@ -1345,7 +1358,7 @@ essentially the simplest form of an if-then-else statement. A simple
|
|||
variation of the expression where the value of the if-statement is
|
||||
used within another statement is as follows:
|
||||
|
||||
x := 3 * if (y < z, y + 1, 2* z) / 2
|
||||
x := 3 * if (y < z, y + 1, 2 * z) / 2
|
||||
|
||||
|
||||
The second form of if-statement resembles the standard syntax found in
|
||||
|
@ -1401,37 +1414,29 @@ The second variation of the if-statement is to allow for the use of
|
|||
Else and If-Else cascading statements. Examples of such statements are
|
||||
as follows:
|
||||
|
||||
Example 1: Example 2:
|
||||
if (x < y) if (x < y)
|
||||
z := x + 3; {
|
||||
else y := z + x;
|
||||
y := x - z; z := x + 3;
|
||||
}
|
||||
else
|
||||
y := x - z;
|
||||
Example 1: Example 2: Example 3:
|
||||
if (x < y) if (x < y) if (x > y + 1)
|
||||
z := x + 3; { y := abs(x - z);
|
||||
else y := z + x; else
|
||||
y := x - z; z := x + 3; {
|
||||
} y := z + x;
|
||||
else z := x + 3;
|
||||
y := x - z; };
|
||||
|
||||
Example 3: Example 4:
|
||||
if (x > y + 1) if (2 * x < max(y,3))
|
||||
y := abs(x - z); {
|
||||
else y := z + x;
|
||||
{ z := x + 3;
|
||||
y := z + x; }
|
||||
z := x + 3; else if (2y - z)
|
||||
}; y := x - z;
|
||||
|
||||
Example 5: Example 6:
|
||||
if (x < y) if (x < y or (x + z) > y)
|
||||
z := x + 3; {
|
||||
else if (2y != z) z := x + 3;
|
||||
{ y := x - z;
|
||||
z := x + 3; }
|
||||
y := x - z; else if (abs(2y - z) >= 3)
|
||||
} y := x - z;
|
||||
else else
|
||||
x * x; {
|
||||
z := abs(x * x);
|
||||
x * y * z;
|
||||
};
|
||||
Example 4: Example 5: Example 6:
|
||||
if (2 * x < max(y,3)) if (x < y) if (x < y or (x + z) > y)
|
||||
{ z := x + 3; {
|
||||
y := z + x; else if (2y != z) z := x + 3;
|
||||
z := x + 3; { y := x - z;
|
||||
} z := x + 3; }
|
||||
else if (2y - z) y := x - z; else if (abs(2y - z) >= 3)
|
||||
y := x - z; } y := x - z;
|
||||
else else
|
||||
x * x; {
|
||||
z := abs(x * x);
|
||||
x * y * z;
|
||||
};
|
||||
|
||||
|
||||
In the case where there is no final else statement and the flow
|
||||
|
@ -1451,7 +1456,7 @@ Special functions dramatically decrease the total evaluation time of
|
|||
expressions which would otherwise have been written using the common
|
||||
form by reducing the total number of nodes in the evaluation tree of
|
||||
an expression and by also leveraging the compiler's ability to
|
||||
correctly optimize such expressions for a given architecture.
|
||||
correctly optimise such expressions for a given architecture.
|
||||
|
||||
3-Parameter 4-Parameter
|
||||
+-------------+-------------+ +--------------+------------------+
|
||||
|
@ -1581,25 +1586,28 @@ examples of string variable definitions:
|
|||
(a) Initialise to a string
|
||||
var x := 'abc';
|
||||
|
||||
(b) Initialise to a string expression
|
||||
(b) Initialise to an empty string
|
||||
var x := '';
|
||||
|
||||
(c) Initialise to a string expression
|
||||
var x := 'abc' + '123';
|
||||
|
||||
(c) Initialise to a string range
|
||||
(d) Initialise to a string range
|
||||
var x := 'abc123'[2:4];
|
||||
|
||||
(d) Initialise to another string variable
|
||||
(e) Initialise to another string variable
|
||||
var x := 'abc';
|
||||
var y := x;
|
||||
|
||||
(e) Initialise to another string variable range
|
||||
(f) Initialise to another string variable range
|
||||
var x := 'abc123';
|
||||
var y := x[2:4];
|
||||
|
||||
(f) Initialise to a string expression
|
||||
(g) Initialise to a string expression
|
||||
var x := 'abc';
|
||||
var y := x + '123';
|
||||
|
||||
(g) Initialise to a string expression range
|
||||
(h) Initialise to a string expression range
|
||||
var x := 'abc';
|
||||
var y := (x + '123')[1:3];
|
||||
|
||||
|
@ -1775,7 +1783,7 @@ needs to be 'updated' to either another vector or sub-range, the
|
|||
vector_view instance can be efficiently rebased, and the expression
|
||||
evaluated as normal.
|
||||
|
||||
exprtk::vector_view<T> view = exprtk::make_vector_view(v, v.size());
|
||||
exprtk::vector_view<T> view = exprtk::make_vector_view(v,v.size());
|
||||
|
||||
symbol_table_t symbol_table;
|
||||
symbol_table.add_vector("v",view);
|
||||
|
@ -1794,7 +1802,7 @@ evaluated as normal.
|
|||
|
||||
[SECTION 15 - USER DEFINED FUNCTIONS]
|
||||
ExprTk provides a means whereby custom functions can be defined and
|
||||
utilized within expressions. The concept requires the user to
|
||||
utilised within expressions. The concept requires the user to
|
||||
provide a reference to the function coupled with an associated name
|
||||
that will be invoked within expressions. Functions may take numerous
|
||||
inputs but will always return a single value of the underlying numeric
|
||||
|
@ -1840,7 +1848,7 @@ function called 'foo':
|
|||
(2) ivararg_function
|
||||
This interface supports a variable number of scalar arguments as input
|
||||
into the function. The function operator interface uses a std::vector
|
||||
specialized upon type T to facilitate parameter passing. The following
|
||||
specialised upon type T to facilitate parameter passing. The following
|
||||
example defines a vararg function called 'boo':
|
||||
|
||||
template <typename T>
|
||||
|
@ -1863,7 +1871,7 @@ example defines a vararg function called 'boo':
|
|||
(3) igeneric_function
|
||||
This interface supports a variable number of arguments and types as
|
||||
input into the function. The function operator interface uses a
|
||||
std::vector specialized upon the type_store type to facilitate
|
||||
std::vector specialised upon the type_store type to facilitate
|
||||
parameter passing.
|
||||
|
||||
Scalar <-- function(i_0, i_1, i_2....., i_N)
|
||||
|
@ -2335,6 +2343,42 @@ Note: For the igeneric_function type, there also needs to be a 'Z'
|
|||
parameter sequence defined in order for the zero parameter trait to
|
||||
properly take effect otherwise a compilation error will occur.
|
||||
|
||||
|
||||
(9) Free Functions
|
||||
The ExprTk symbol table supports the registration of free functions
|
||||
and lambdas (anonymous functors) for use in expressions. The basic
|
||||
requirements are similar to those found in ifunction derived user
|
||||
defined functions. This includes support for free functions using
|
||||
anywhere from zero up to fifteen input parameters of scalar type, with
|
||||
a return type that is also scalar. Furthermore such functions will by
|
||||
default be assumed to have side-effects and hence will not participate
|
||||
in constant folding optimisations.
|
||||
|
||||
In the following example, a two input parameter free function named
|
||||
'compute', and a three input parameter lambda will be registered with
|
||||
the given symbol_table instance:
|
||||
|
||||
|
||||
double compute(double v0, double v1)
|
||||
{
|
||||
return 2.0 * v0 + v1 / 3.0;
|
||||
}
|
||||
|
||||
.
|
||||
.
|
||||
.
|
||||
|
||||
typedef exprtk::symbol_table<double> symbol_table_t;
|
||||
|
||||
symbol_table_t symbol_table;
|
||||
|
||||
symbol_table.add_function("compute", compute);
|
||||
|
||||
symbol_table.add_function("lambda",
|
||||
[](double v0, double v1, double v2) -> double
|
||||
{ return v0 / v1 + v2; });
|
||||
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
[SECTION 16 - EXPRESSION DEPENDENTS]
|
||||
|
@ -2443,7 +2487,7 @@ associated assignments:
|
|||
(5) None x + y + z
|
||||
|
||||
|
||||
Note: In expression 4, both variables 'z' and 'w' are denoted as being
|
||||
Note: In expression 4, both variables 'w' and 'z' are denoted as being
|
||||
assignments even though only one of them can ever be modified at the
|
||||
time of evaluation. Furthermore the determination of which of the two
|
||||
variables the modification will occur upon can only be known with
|
||||
|
@ -2489,7 +2533,7 @@ associated with a given expression instance.
|
|||
|
||||
However as an expression can have more than one symbol table instance
|
||||
associated with itself, when building more complex systems that
|
||||
utilize many expressions where each can in turn utilize one or more
|
||||
utilise many expressions where each can in turn utilise one or more
|
||||
variables from a large set of potential variables, functions or
|
||||
constants, it becomes evident that grouping variables into layers of
|
||||
symbol_tables will simplify and streamline the overall process.
|
||||
|
@ -2559,7 +2603,7 @@ own instances of those variables. Examples of such variables could be:
|
|||
(2) customer_name
|
||||
|
||||
|
||||
The following is a diagram depicting the possible version of the
|
||||
The following is a diagram depicting the possible version of the
|
||||
denoted symbol table hierarchies. In the diagram there are two unique
|
||||
expressions, each of which have a reference to the Global constant,
|
||||
functions and variables symbol tables and an exclusive reference to a
|
||||
|
@ -2589,8 +2633,8 @@ local symbol table.
|
|||
|
||||
|
||||
Bringing all of the above together, in the following example the
|
||||
hierarchy of symbol tables are instantiated and initialised. An
|
||||
expression that makes use of various elements of each symbol table is
|
||||
hierarchy of symbol tables are instantiated and initialised. An
|
||||
expression that makes use of various elements of each symbol table is
|
||||
then compiled and later on evaluated:
|
||||
|
||||
typedef exprtk::symbol_table<double> symbol_table_t;
|
||||
|
@ -2722,7 +2766,7 @@ expressions:
|
|||
In this scenario one can use the 'dependent_entity_collector'
|
||||
component as described in [Section 16] to further determine which of
|
||||
the registered variables were actually used in the given expression.
|
||||
As an example once the set of utilized variables are known, any
|
||||
As an example once the set of utilised variables are known, any
|
||||
further 'attention' can be restricted to only those variables when
|
||||
evaluating the expression. This can be quite useful when dealing with
|
||||
expressions that can draw from a set of hundreds or even thousands of
|
||||
|
@ -3427,8 +3471,8 @@ values.
|
|||
|
||||
expression.value();
|
||||
|
||||
printf("Result0: %15.5f\n",result0 );
|
||||
printf("Result1: %s\n" ,result1.c_str());
|
||||
printf("Result0: %15.5f\n", result0 );
|
||||
printf("Result1: %s\n" , result1.c_str());
|
||||
|
||||
|
||||
In the example above, the expression will compute two results. As such
|
||||
|
@ -3436,7 +3480,7 @@ two result variables are defined to hold the values named result0 and
|
|||
result1 respectively. The first is of scalar type (double), the second
|
||||
is of string type. Once the expression has been evaluated, the two
|
||||
variables will have been updated with the new result values, and can
|
||||
then be further utilized from within the calling program.
|
||||
then be further utilised from within the calling program.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -3753,12 +3797,12 @@ overloads, the definitions of which are:
|
|||
|
||||
(1) No variables
|
||||
(2) One variable called x
|
||||
(3) Two variable called x and y
|
||||
(3) Three variable called x, y and z
|
||||
(3) Two variables called x and y
|
||||
(3) Three variables called x, y and z
|
||||
|
||||
|
||||
An example use of each of the three overloads for the compute routine
|
||||
is as follows:
|
||||
Example uses of each of the three overloads for the compute routine
|
||||
are as follows:
|
||||
|
||||
T result = T(0);
|
||||
|
||||
|
@ -3803,11 +3847,11 @@ is as follows:
|
|||
|
||||
(d) integrate
|
||||
This free function will attempt to perform a numerical integration of
|
||||
a single variable compiled expression over a defined range and given
|
||||
step size. The numerical integration is based on the three point form
|
||||
of the Simpson's rule. The integrate function has two overloads, where
|
||||
the variable of integration can either be passed as a reference or as
|
||||
a name in string form. Example usage of the function is as follows:
|
||||
a single variable compiled expression over a specified range and step
|
||||
size. The numerical integration is based on the three point form of
|
||||
Simpson's rule. The integrate function has two overloads, where the
|
||||
variable of integration can either be passed as a reference or as a
|
||||
name in string form. Example usage of the function is as follows:
|
||||
|
||||
typedef exprtk::parser<T> parser_t;
|
||||
typedef exprtk::expression<T> expression_t;
|
||||
|
@ -3863,7 +3907,7 @@ function is as follows:
|
|||
|
||||
....
|
||||
|
||||
// Differentiate expression where value of x = 12.3 using a reference
|
||||
// Differentiate expression at value of x = 12.3 using a reference
|
||||
// to the x variable
|
||||
x = T(12.3);
|
||||
T derivative1 = exprtk::derivative(expression,x);
|
||||
|
@ -4047,7 +4091,7 @@ expressions. As an example, lets take the following expression:
|
|||
1 / sqrt(2x) * e^(3y)
|
||||
|
||||
|
||||
Let's say we would like to determine which sub-part of the expression
|
||||
Lets say we would like to determine which sub-part of the expression
|
||||
takes the most time to evaluate and perhaps attempt to rework the
|
||||
expression based on the results. In order to do this we will create a
|
||||
text file called 'test.txt' and then proceed to make some educated
|
||||
|
@ -4133,7 +4177,7 @@ into account when using ExprTk:
|
|||
|
||||
(09) The life-time of objects registered with or created from a
|
||||
specific symbol-table must span at least the life-time of the
|
||||
compiled expressions which utilize objects, such as variables,
|
||||
compiled expressions which utilise objects, such as variables,
|
||||
of that symbol-table, otherwise the result will be undefined
|
||||
behavior.
|
||||
|
||||
|
@ -4289,7 +4333,15 @@ into account when using ExprTk:
|
|||
performance critical code paths, and should instead occur
|
||||
entirely either before or after such code paths.
|
||||
|
||||
(32) Before jumping in and using ExprTk, do take the time to peruse
|
||||
(32) Deep copying an expression instance for the purposes of
|
||||
persisting to disk or otherwise transmitting elsewhere with the
|
||||
intent to 'resurrect' the expression instance later on is not
|
||||
possible due to the reasons described in the final note of
|
||||
Section 10. The recommendation is to instead simply persist the
|
||||
string form of the expression and compile the expression at
|
||||
run-time on the target.
|
||||
|
||||
(33) Before jumping in and using ExprTk, do take the time to peruse
|
||||
the documentation and all of the examples, both in the main and
|
||||
the extras distributions. Having an informed general view of
|
||||
what can and can't be done, and how something should be done
|
||||
|
|
Loading…
Reference in New Issue