C++ Logo

std-proposals

Advanced search

[std-proposals] long return lambda

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Tue, 11 Apr 2023 14:16:54 +0100
Today I wrote the following function for a microcontroller:

    bool Serial(char *const p)
    {
    # define BAIL { strcpy(p, "0000000000000000"); return false; }

        int32_t p32[2u];

        if ( (SUCCESS != fpgaReadInt32(0x00f2, &p32[0])) || (0 ==
(p32[0] & 1)) ) BAIL

        if ( SUCCESS != fpgaReadInt32(0x00f6, &p32[0]) ) BAIL

        if ( SUCCESS != fpgaReadInt32(0x00fa, &p32[1]) ) BAIL

        sprintf(p + 0u, "%08lx", static_cast<long unsigned>(p32[0]));
        sprintf(p + 16u, "%08lx", static_cast<long unsigned>(p32[1]));

        return true;

    # undef BAIL
    }

I would have liked to use a lambda instead of a macro there, but then
I would have to write:

    bool Serial(char *const p)
    {
        auto BAIL = [p](void)->void { strcpy(p, "0000000000000000"); };

        int32_t p32[2u];

        if ( (SUCCESS != fpgaReadInt32(0x00f2, &p32[0])) || (0 ==
(p32[0] & 1)) ) { BAIL(); return false; }

        if ( SUCCESS != fpgaReadInt32(0x00f6, &p32[0]) ) { BAIL();
return false; }

        if ( SUCCESS != fpgaReadInt32(0x00fa, &p32[1]) ) { BAIL();
return false; }

        sprintf(p + 0u, "%08lx", static_cast<long unsigned>(p32[0]));
        sprintf(p + 16u, "%08lx", static_cast<long unsigned>(p32[1]));

        return true;
    }

So I thinking, what if we had a 'long return lamda'? The return
statement from a 'long return lambda' is treated as a return statement
from the enclosing function. As follows:

    bool Serial(char *const p)
    {
        auto BAIL = [p](void) -> long return bool { strcpy(p,
"0000000000000000"); return false; };

        int32_t p32[2u];

        if ( (SUCCESS != fpgaReadInt32(0x00f2, &p32[0])) || (0 ==
(p32[0] & 1)) ) BAIL();

        if ( SUCCESS != fpgaReadInt32(0x00f6, &p32[0]) ) BAIL();

        if ( SUCCESS != fpgaReadInt32(0x00fa, &p32[1]) ) BAIL();

        sprintf(p + 0u, "%08lx", static_cast<long unsigned>(p32[0]));
        sprintf(p + 16u, "%08lx", static_cast<long unsigned>(p32[1]));

        return true;
    }

Of course, you wouldn't be able to store one of these lambdas inside a
normal 'std::function', you'd need to store it inside a
'std::long_return_function' instead.

A few important points:
(1) The return type of a 'long return lambda', if not omitted, must be
implicitly-convertible to the return type of the enclosing function.
(2) You cannot analyse the return value from a 'long return lambda'
inside the enclosing function. For example the initialisation of a
variable inside the enclosing function cannot involve the invocation
of a 'long return lambda', so the following isn't valid:

    int MyFunc(void)
    {
        auto monkey = []()->long return { return 5; }

        int i = monkey(); // ill-formed - compiler must issue diagonstic
    }

(3) However you can analyse the return value higher up the function
call hierarchy:

    int Func2(void)
    {
        auto Bail = []() -> long return int { return 5; }

        // int i = Bail(); - This would be invalid

        Bail();
    }

    int Func(void)
    {
        int i = Func2(); // This is valid
    }

Received on 2023-04-11 13:17:06