简体   繁体   中英

Can boost::asio::yield_context set a std::error_code instead of boost::system::error_code?

I'm writing a C++11 networking library that uses Boost.Asio under the hood. I want to expose an API that allows users to use stackful coroutines.

boost::asio::yield_context overloads the [] operator so that an asynchronous operation may set an error code instead of throwing an exception. For example:

std::size_t n = my_socket.async_read_some(buffer, yield[ec]);
if (ec)
{
    // An error occurred.
}

My library uses std::error_code and std::system_error to report errors. My question is how can I make boost::asio::yield_context set a std::error_code instead of boost::system::error_code ? I'd like users of my library to be able to do this:

std::error_code ec;
auto result = remoteProdedureCall(args, yield[ec]);
if (ec)
    handleError();

where remoteProcedureCall would look something like:

Result remoteProcedureCall(Args args, boost::asio::yield_context yield)
{
    //...
    boost::asio::async_write(socket_, argsBuffer, yield);
    boost::asio::async_read(socket_, resultBuffer, yield);
    if (invalidResult())
        // Return a std::error_code via the yield object somehow???
        // (My error codes belong to a custom error_category)
    // ...
    return result;
}

PS I should indicate that my library uses error codes that belong to a custom error_category .

I ended-up doing something much simpler than trying to coerce yield_context into setting an std::error_code :

// This overload sets a std::error_code if there's an error.
Result remoteProcedureCall(Args args, boost::asio::yield_context yield,
                           std::error_code& userErrorCode)
{
    //...
    boost::system::error_code ec;
    boost::async_write(socket_, buffer, yield[ec];
    if (ec)
    {
        userErrorCode = toStdErrorCode(ec);
        return Result();
    }
    // ...
    if (someNonBoostError)
    {
        userErrorCode = make_error_code(myCustomErrorCode);
        return Result();
    }
    // ...
    return result;
}

// This overload throws an exception if there's an error
Result remoteProcedureCall(Args args, boost::asio::yield_context yield)
{
    std::error_code ec;
    auto result = remoteProcedureCall(args, yield, ec);
    if (ec)
        throw std::system_error(ec);
    return result;
}

where toStdErrorCode converts from a boost::system::error_code to a std::error_code , as per Sam's answer (also see this related question ).


Even simpler would be to make remoteProcedureCall take an optional pointer to an error_code . This avoids having duplicate functions: one that sets the error code, and another that throws an exception.

This should work, assuming ec is a boost::system_error::error_code

std::make_error_code( static_cast<std::errc::errc>(ec.value()) );

I believe the boost::system::errc::errc_t enums are mapped to the same value in std::errc .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM