Ответ 1
Основное отличие состоит в том, что std::error_condition
является портативным (независимым от платформы), а std::error_code
зависит от платформы. Как правило, низкоуровневый платформозависимый код генерирует error_codes
, а клиентский код сравнивает эти error_codes
с независимыми от платформы error_conditions
.
19.5 [syserr] определяет длинный список стандартных (и переносных) условий ошибки (например, errc::no_such_file_or_directory
), которые явно связаны с определенными значениями errno
(например, ENOENT
). В результате вам не нужно знать полный список возможных значений errno
или GetLastError()
, сгенерированных в вашей системе. Вам нужно знать только стандартные значения, относящиеся к вашему коду. Например, реализация вашей библиотеки может выглядеть так:
void MyLibraryClass::foo(std::error_code &ec)
{
// whatever platform dependent operation that might set errno
// possibly with alternative platform-dependent implementations
ec = make_error_code(errno);
}
Затем ваш код клиента проверяет, соответствует ли error_code
конкретному error_condition
:
error_code ec;
myLibraryInstance.foo(ec);
if (!ec)
{
// success
}
else if (errc::no_such_file_or_directory == ec)
{
// no_such_file_or_directory
}
else
{
// unknown or unexpected error
}
В вашем случае вы, вероятно, определите свое собственное перечисление ошибок (только одно перечисление) и пометьте его как error_conditions
, чтобы включить автоматическое преобразование:
namespace commons
{
namespace dynlib
{
enum class errc {LibraryFailedToLoad=1, LibraryFailedToUnload, SymbolNotFound};
}
}
namespace std
{
template<> struct is_error_condition_enum<commons::dynlib::errc> : true_type {};
}
// TODO: implement make_error_code and make_error_condition
Затем вы можете перевести результат различных зависимых на платформе операций в соответствующий error_condition
(или error_code
, если хотите):
void DynLibLoader::open(std::error_code &ec)
{
// possibly implement the windows version here as well
if (NULL == dlopen(filename, flag))
{
ec = make_error_code(errc::LibraryFailedToLoad);
}
}
Ваш код клиента сравнивает код ошибки с возможными условиями ошибки, как указано выше:
error_code ec;
dynLibLoader.open(ec);
if (!ec)
{
// success
}
else if (commons::dynlib::errc::LibraryFailedToLoad == ec)
{
// Library Failed To Load
}
else
{
// unknown or unexpected error
}
Обратите внимание, что перечисление commons::dynlib::errc::LibraryFailedToLoad
автоматически преобразуется в error_condition
(используя предоставленный метод make_error_condition
), потому что commons::dynlib::errc
помечен is_error_condition_enum
.
Отображение error_category
в пространство имен, вероятно, является личным предпочтением, однако оно кажется немного искусственным. В этом конкретном случае верно, что имеет смысл иметь категорию для пространства имен dynlib
, но было бы легко найти примеры, где было бы целесообразно иметь категории, распространяющие несколько пространств имен. В некоторых случаях может быть значимым и практичным иметь все ваши разные перечисления ошибок в уникальном пространстве имен (например, commons::errors
).