Search code examples
c++c++17variadic-templates

How can I use fold expressions to implement a "domino" or "cascading" update function?


I'm writing a variadic templated function that should implement a "domino" update. That is to say: given a predicate p, it should iterate over multiple lvals (passed by reference) and assign val to them, until p(val, lval) returns false at which point the process stops.

This is my current implementation:

#include <iostream>
#include <functional>

template<class Val, class P>
void domino_update(P, Val&) {}

template<class Val, class Lval, class... More, class P>
void domino_update(P p, Val&& val, Lval& lval, More&... more)
{
    if (p(val, lval)) {
        lval = val; // No need to forward since it'd potentially chain more copies anyway
        domino_update(p, val, more...);
    }
}

int main(int, char**)
{
    int i = 8, j = 9, k = 1;
    domino_update(std::less{}, 2, i, j, k);
    std::cout << i << ' ' << j << ' ' << k << '\n'; // Prints 2 2 1
    return 0;
}

However, I don't like the fact that it's recursive.

Can I use a fold expression to avoid using recursion (and avoid the need to implement a base case for the template), while maintaining the short-circuiting logic (i.e., p should not be called again once it has returned false)? How?


Solution

  • Here's one way:

    template <class P, class Val, class... Lvals>
    void domino_update(P p, Val&& val, Lvals&&... lval) {
        ((/*if*/        p(val, lval)
          /*then*/      && (lval = val, true))
          /*and next*/  && ...);
    }
    

    Demo