【问题标题】:Can boost::asio::yield_context set a std::error_code instead of boost::system::error_code?boost::asio::yield_context 可以设置 std::error_code 而不是 boost::system::error_code 吗?
【发布时间】:2015-03-14 09:39:08
【问题描述】:

我正在编写一个在底层使用 Boost.Asio 的 C++11 网络库。我想公开一个允许用户使用堆栈式协程的 API。

boost::asio::yield_context 重载[] 运算符,以便异步操作可以设置错误代码而不是引发异常。例如:

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

我的库使用std::error_codestd::system_error 报告错误。我的问题是如何让boost::asio::yield_context 设置std::error_code 而不是boost::system::error_code?我希望我的图书馆的用户能够这样做:

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

remoteProcedureCall 看起来像这样:

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;
}

P.S.我应该指出我的库使用属于自定义 error_category 的错误代码。

【问题讨论】:

  • 我意识到我所要求的可能是不可能的,但有人可能会找到一个聪明的技巧或黑客来完成这项工作。或者,也许我的做法是错误的。
  • 一个想法可能是在boost::asio::basic_yield_context周围使用某种包装器。
  • 我可以重载operator+(yield_context&, std::error_code&),以便它返回一个包含原始yield_contextyield_context_wrapper,以及一个指向用户std::error_code 变量的指针。我还将提供一个采用yield_contextyield_context_wrapper 转换构造函数。然后,我的 API 函数将采用 yield_context_wrapper 参数而不是 yield_context,从而获得对用户的 std::error_code 变量的访问权限。

标签: c++ c++11 boost boost-asio coroutine


【解决方案1】:

我最终做了一些比试图强迫yield_context 设置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;
}

根据 Sam 的 answertoStdErrorCodeboost::system::error_code 转换为 std::error_code(另请参阅相关的 question)。


更简单的方法是让remoteProcedureCall 采用指向error_code 的可选指针。这避免了重复的函数:一个设置错误代码,另一个抛出异常。

【讨论】:

  • 这种方法的缺点是它有效地使我的 API 中的函数数量增加了一倍。
【解决方案2】:

这应该可以工作,假设 ecboost::system_error::error_code

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

我相信boost::system::errc::errc_t 枚举映射到std::errc 中的相同值。

【讨论】:

  • 谢谢,但我需要反过来。我的函数想通过yield 对象返回一个std::error_code。我的错误代码(属于自定义错误类别)不映射到 std::errc 中的代码,也不映射到 boost::system::errc
猜你喜欢
  • 1970-01-01
  • 2021-05-21
  • 2018-04-01
  • 2012-04-27
  • 2014-01-29
  • 1970-01-01
  • 2012-08-25
  • 1970-01-01
  • 2011-11-28
相关资源
最近更新 更多