template<typename Subclass, typename... Children>
class sp::VariableUser< Subclass, Children >
Base for anything that uses the expression variable system.
This class exists as an abstraction for anything that uses variables. This might be an expression, or it might be a system of multiple expressions that could be intended to be evaluated in a particular way. For example, one of the variables might be a buffer to write to rather than an expression to evaluate. That is why it has a binding mechanism rather than an evaluation mechanism. This design also allows for a partially bound object - where some of the variables are bound, but not all.
Most-derived classes that derive from this one (i.e: the Subclass template parameter) must define:
- A default constructor if there are no bound variables.
- A constructor taking one argument for each child (convertible to the type of that child) that calls the constructor for VariableUser.
- A template alias (or other templated type) called ReplaceChildren. This should return the type that is equivalent to Subclass, but with its children (i.e: the arguments that would be passed as Children) changed to a given list of types. This is used by bind() to change variable types to bound variable types, and by Substitute to perform substitution recursively.
A subclasses may define an operator() that accepts no arguments. If it does, it should require IsFullyBound to be true. This class provides an operator() that accepts as many arguments as are unbound, provided this is not zero. This class has an operator()() that forwards its arguments to bind(), and then calls the subclass's operator()(). If wanted, it must be imported into the most derived class with a using declaration.
- Template Parameters
-
Subclass | A curiously recurring template parameter for the most-derived class. |
Children | All VariableUser-derived types that are directly used by the subclass. These must all be derived from VariableUser. |
template<typename Subclass , typename... Children>
template<typename Old , typename New >
Recursively substitute the given old user with the given new user.
An example use might be to replace one expression with another within a larger expression.
This is intended to be used for abstract algebra at compile time. To substitute a variable with a value at runtime, use bind().
- Template Parameters
-
Old | The old user type to replace. |
New | The new user type to replace with. |
template<typename Subclass , typename... Children>
Get an unused variable name.
If A is a variable user, and B is a variable user with the same variables as A, but with A::getUnusedVariableName(0) through A::getUnusedVariableName(N - 1) as well, then A::getUnusedVariableName(N) == B::getUnusedVariableName(0).
The returned variable name may come from a unicode private use area, as this is intended for use by automated algebra systems' temporary variables.
- Parameters
-
i | Guarantee non-collision when multiple variables are needed by setting this to a small unique non-negative value for each needed variable. |
- Returns
- A variable name that is not used already by the variable user.
template<typename Subclass , typename... Children>
template<typename... Ts>
requires (!DeferSubclass<Ts...>::
IsFullyBound)
constexpr decltype(auto) sp::VariableUser< Subclass, Children >::operator() |
( |
Ts &&... |
values | ) |
const |
|
constexpr |
Calls operator() on the result of binding this object to a set of variables.
For this to work, the return value of bind() must have an operator() that takes no arguments. Unfortunately, due to C++ name resolution rules that apply to CRTPs, the classes that want to use this when they're the most derived classes must import it using something like using VariableUser::operator();
.