Basic expression tutorial
The expression is the central entity of the KFR framework.
Input expressions can be read from and output expressions can be written to. A class can be an input and output expression at the same time. univector is an example of such a class.
The data type of an input expression can be determined by calling value_type_of. However, not all expressions have their types specified. In such cases, value_type_of returns the special type generic.
The size (length) of an expression can also be specified or left unspecified. counter is an example of a generic (untyped) expression without a size.
Calling functions
Passing an expression to a function doesn’t calculate the value immediately. Instead, a new expression is created.
Example:
auto a = counter(); // a is an expression without type
auto b = a * 2 + 1; // b is an expression without type
univector<int, 5> c = b; // fill c with values 1, 3, 5, 7, 9
In the example above, only the last line performs the actual calculations. This is an example of lazy evaluation.
univector<int, 6> d = sqr(counter());
print(d); // prints 0, 1, 4, 9, 16, 25
const double w = c_pi<double> * 0.125;
univector<double, 6> e = sin(counter() * w);
print(e); // prints 0 0.382683 0.707107 0.92388 1 0.92388
counter()
counter() is an expression that outputs values from 0 to infinity.
This expression has no specified type, so it can be used in any expression.
We will use the following simple function to print the first ten values of an expression:
template <typename E>
void print10(const E& e)
{
univector<double, 10> v = e; // do actual calculations
println(v); // print result
}
Examples:
print10(counter() * 2); // 0, 2, 4, 6, 8, 10, 12, 14, 16, 18
print10(1 << (counter()+1)); // 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024
print10(clamp(counter(), 2, 7)); // 2, 2, 2, 3, 4, 5, 6, 7, 7, 7
auto freq = counter() * c_pi<double, 2> * 1000.0 / 44100.0;
auto sine = sin(freq);
print10(sine); // first ten samples of a 1000 Hz sinusoid at 44100 Hz
Reviewed and updated for KFR 7 in Oct 2026.