As DMGregory wrote, the key is to move the responsibility for checking whether or not an entity is relevant for a system out of the system's update function.
Archetypes are one approach to this, but I would like to present a way that can do this without this additional abstraction layer.
- Each system maintains an own array of component-tuples (structures of pointers to a set of components that belong to the same entity) that are relevant to it.
- When an entity is created, or when an entity's composition changes, you pass it to a method of each system that checks if that entity has the required components for this system, and then adds/removes the corresponding component tuple in that array.
- When a system is updated, it iterates over that array of component tuples.
Changes to entities will probably a lot less common than executing the functions that update them. So by pre-processing the eligibility for various systems on composition changes, you avoid checking them again in every single update even though the composition didn't change. That makes your update methods faster and shorter.