On Wednesday, November 15, 2023, Frederick Virchanza Gotham wrote:

This would be very useful for data logging, or for implementing
functions that work along the same lines as 'strtok'.


I've thought of a really good use for this.

I have a program running a superloop on an Arduino microcontroller. In order to keep the iteration time of the superloop below 100 milliseconds, I only allow it to send one message per iteration of the superloop.

To send a message, I call:

    gSimGsm.send("whatever");

which will return true if it sent a message, or return false if it failed because there had already been one message sent in that iteration of the superloop.

And so I wrote a class called SuperloopManager, which you can use as follows:

    gSuperloopManager.DeferUntilTrue([]{ send("whatever"); });

The above line of code will immediately try to send a message, but if it cannot because there has already been a message sent in the current iteration of the superloop, then it will defer it until the next iteration. It will keep invoking that lambda upon each iteration of the superloop until the lambda returns true.

But the problem is that if the message keeps getting deferred again and again and again, then the program might reach a point where it enqueues the same message a second time. Then we'll have two of the same message waiting in the queue, and if it happens a third time and a fourth time then the queue will become full and my microcontroller will reset.

To remedy this, I was considering putting a unique ID at every callsite, something like:

    enum { msg_monkey, msg_donkey, msg_goat };

    gSuperloopManager.DeferUntilTrue(msg_monkey, []{ send("whatever"); });

And then I would check the ID to ensure that the message in question isn't already in the queue.

But it would be more convenient to do:

    class SuperloopManager {
        template<typename = decltype([]{})>
        void DeferUntilTrue(std::function<void(void)> &&arg)
        {
            static char dummy;

            // code here
        }
    };

And then I could use the address of 'dummy' as a compile-time constant to identify the message and to disallow a double-queuing.