C++ Logo

std-proposals

Advanced search

Re: Initialisers in ternary operators

From: Barry Revzin <barry.revzin_at_[hidden]>
Date: Mon, 14 Sep 2020 07:41:04 -0500
On Mon, Sep 14, 2020 at 5:00 AM Jorg Brown via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> Oh, I should add, there are two exemplary near-misses of what I want.
>
> Exemplar 1:
>
> #define ASSIGN_OR_RETURN(var, optional) \
> if (auto templine(__LINE__) = optional; !!templine(__LINE__)) \
> var = std::move(*templine(__LINE__)); \
> else \
> return nullopt
>
> The trouble is, while this code works great for this:
>
> UserId uid;
> if (non_default) ASSIGN_OR_RETURN(uid, GetUserId());
>
> It doesn't work for this:
>
> ASSIGN_OR_RETURN(Location uloc, uid.GetLocation());
>
> Because in the second case, the definition of the "uloc" local variable
> happens within the if. So when the if exits, the variable is gone.
>
> You'd think you could get around this by flipping the if around, so that
> the definition of the new variable is not inside the scope of the if:
>
> #define ASSIGN_OR_RETURN(var, optional) \
> if (auto templine(__LINE__) = optional; !templine(__LINE__)) \
> return nullopt; \
> var = std::move(*templine(__LINE__))
>
>
> But now you have the other problem: the "templine(__LINE__)" temporary
> variable was created inside the if's conditional, so it goes out-of-scope
> before we can move out of it. (Also, this is two statements, so
> ASSIGN_OR_RETURN can no longer appear on the right side of an if statement,
> without being enclosed in braces.)
>
> In any case, these demonstrate the fundamental problem: when a boolean
> expression is being tested, but the evaluation of that expression generates
> additional rvalue data that is only valid if the boolean is "true", it's
> surprisingly difficult to retrieve the extra data.
>
> -- Jorg
>

I think you're looking for this:

#define ASSIGN_OR_RETURN(var, optional) \
    do { \
        auto r = optional; \
        if (!r) return nullopt; \
        var = std::move(*r); \
    } while(0)

Which with statement-expressions (back to the theme of the thread) would
actually now appear on the right-hand side of assignment or initialization:

#define TRY_OPT(optional) \
    ({ \
        auto r = optional; \
        if (!r) return nullopt; \
        std::move(*r); \
    })

Location uloc = TRY_OPT(uid.GetLocation());

Barry

Received on 2020-09-14 07:41:19