One can see how writing:

struct { 
  static consteval auto name() { return "foobar"; } 
  float value; 
} foobar;

for 200 controls would get boring quick. In addition, the implementation of our processing function is not as clean as we'd want: in an ideal world, it would be just:

void operator()() { outputs.out = inputs.a + inputs.b; }

Thankfully, we can introduce our own custom abstractions without breaking anything: the only thing that matters is that they follow the "shape" of what a parameter is.

This shape is defined (as a first approximation) as follows:

template<typename T>
concept parameter = requires (T t) { t.value = {}; };

In C++ parlance, this means that a type can be recognized as a parameter if

  • It has a member called value.
  • This member is assignable with some default value.

For instance:

struct bad_1 {
  const int value;

struct bad_2 {
  void value();

class bad_3 {
  int value;

are all invalid parameters.

This can be ensured easily by asking the compiler:


static_assert is a C++ feature which allows to check a predicate at compile-time. If the predicate is false, the compiler will report an error.

Avendish will simply not recognize them and they won't be accessible anywhere.

Here are examples of valid parameters:

struct good_1 {
  int value;

struct good_2 {
  std::string value;

template<typename T>
struct assignable {
  T& operator=(T x) { 
    printf("I changed !");
    this->v = x;
    return this->v;
  T v;

class good_3 {
    assignable<double> value;

This can be ensured again by asking the compiler:


Avendish provides an helper library, halp (Helper Abstractions for Literate Programming), which match this pattern. However, users are encouraged to develop their own abstractions that fit their preferred coding style :-)