Я пишу сетевую библиотеку C ++ 11, которая использует Boost.Asio под капотом. Я хочу показать API, который позволяет пользователям использовать сложную сопрограммы.
boost::asio::yield_context
перегружает []
оператор, так что асинхронная операция может установить код ошибки, а не генерировать исключение. Например:
std::size_t n = my_socket.async_read_some(buffer, yield[ec]);
if (ec)
{
// An error occurred.
}
Моя библиотека использует std::error_code
а также std::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;
}
Постскриптум Я должен указать, что моя библиотека использует коды ошибок, которые принадлежат error_category
,
Я закончил тем, что делал что-то намного проще, чем пытаться заставить 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;
}
где toStdErrorCode
преобразует из boost::system::error_code
к std::error_code
согласно Сэму ответ (также см. это связано вопрос).
Еще проще было бы сделать remoteProcedureCall
взять необязательный указатель на error_code
, Это позволяет избежать дублирования функций: одна устанавливает код ошибки, а другая — исключение.
Это должно работать, предполагая, ec
это boost::system_error::error_code
std::make_error_code( static_cast<std::errc::errc>(ec.value()) );
Я верю boost::system::errc::errc_t
перечисления отображаются на одно и то же значение в std::errc
.