Search code examples
c++algorithmfunctionc++23std-expected

How can I return directly result of a function call returning std::expected?


let's take this short example:

std::expected<std::any, Fault> doN(int n) 
{
    switch (n) 
    {
        case 1: return do1();
        case 2: return do2();
        // ...
    }
}

std::expected<int, Fault> do1()
{
    if (error)
    {
        return std::unexpected<Fault>({/* ... */});
    }
    return 23;
}

If I do it this way and call auto result = doN(1) without errors, then result.value() type is std::expected<int, Fault> and not int (without mentioning the any_cast).

The way I found to solve this is to destruct the result of the inner call:

std::expected<std::any, Fault> doN(int n)
{
    switch (n) 
    {
        case 1: 
            auto value = do1();
            if (value.has_value()) {
                return value.value();
            }
            return std::unexpected(value.error());
        // ...
    }
}

The type doN(1).value() is int.

So my question is: How can I simplify that? Is there a way to return the function call result?


Solution

  • How can I simplify that? Is there a way to return the function call result?

    In order to simplify your approach, you could use std::expected::transform. Something like:

    return do1().transform([](int value) { return std::any(value); });
    

    The transform method does the following:

    • It checks if the std::expected contains a value (do1().has_value())
    • If it has a value, it applies the lambda function to transform that value (std::any(value)) and returns a new std::expected with the transformed value
    • If it has an error, it simply propagates that error without calling the lambda.

    That means, might be able to write:

    // Helper function to convert any std::expected<T, Fault> to std::expected<std::any, Fault>
    template<typename T>
    std::expected<std::any, Fault> to_any(std::expected<T, Fault> exp) 
    {
        return exp.transform([](auto value) { return std::any(value); });
    }
    
    // Function that calls the appropriate function based on input
    std::expected<std::any, Fault> doN(int n) 
    {
        switch (n) {
            case 1: return to_any(do1());
            case 2: return to_any(do2());
            // ...
            default: return std::unexpected<Fault>({/* some error */});
        }
    }
    

    ((See live example demo))