我想,以取代外部库(如升压)尽可能地与他们在标准C ++等价物(如果存在),这是可能的,以减少依赖关系,因此我不知道是否存在一个安全的方式来转换boost::system::error_code
到std::error_code
。 伪代码示例:
void func(const std::error_code & err)
{
if(err) {
//error
} else {
//success
}
}
boost::system::error_code boost_err = foo(); //foo() returns a boost::system::error_code
std::error_code std_err = magic_code_here; //convert boost_err to std::error_code here
func(std_err);
最重要的是不完全一样的错误,只是如此接近越好,最后,如果是一个错误或没有。 是否有任何智能的解决方案?
提前致谢!
由于C ++ - 11(STD :: ERRC), 升压/系统/ error_code.hpp映射相同的错误代码,以标准:: ERRC ,这是在系统头定义system_error
。
您可以比较这两个枚举和,因为它们都似乎是基于POSIX标准,他们应该在功能上等同。 可能需要强制。
例如,
namespace posix_error
{
enum posix_errno
{
success = 0,
address_family_not_supported = EAFNOSUPPORT,
address_in_use = EADDRINUSE,
address_not_available = EADDRNOTAVAIL,
already_connected = EISCONN,
argument_list_too_long = E2BIG,
argument_out_of_domain = EDOM,
bad_address = EFAULT,
bad_file_descriptor = EBADF,
bad_message = EBADMSG,
....
}
}
和std::errc
address_family_not_supported error condition corresponding to POSIX code EAFNOSUPPORT
address_in_use error condition corresponding to POSIX code EADDRINUSE
address_not_available error condition corresponding to POSIX code EADDRNOTAVAIL
already_connected error condition corresponding to POSIX code EISCONN
argument_list_too_long error condition corresponding to POSIX code E2BIG
argument_out_of_domain error condition corresponding to POSIX code EDOM
bad_address error condition corresponding to POSIX code EFAULT
我有这个完全一样的问题,因为我想用std::error_code
而且还使用了使用其他Boost库boost::system::error_code
(如提高ASIO)。 接受答案的工作由处理的错误代码std::generic_category()
因为他们是从升压转换器的一般错误代码一个简单的演员,但它不会为你想要处理自定义的错误类别,以及一般情况下工作。
所以,我创建了下面的代码作为一个通用boost::system::error_code
至- std::error_code
转换器。 其工作原理是动态创建std::error_category
每个垫片boost::system::error_category
,转发到底层增压误差类的调用。 由于错误类别需要单身(单身或类似在这种情况下,至少)我不认为会有多大的内存爆炸。
我也只是转换boost::system::generic_category()
对象使用std::generic_category()
因为他们应该做的是相同的。 我本来想行的通的system_category()
但是在VC ++ 10它打印出错误的信息(我认为它应该打印出来你会得到什么测试FormatMessage
,但它似乎使用strerror
,升压使用FormatMessage
为预期)。
要使用它只需调用BoostToErrorCode()
定义如下。
只是一个警告,我就是这个今天撰文称,所以它只有基本的测试。 您可以使用它,你喜欢的任何方式,但你在你自己承担风险。
//==================================================================================================
// These classes implement a shim for converting a boost::system::error_code to a std::error_code.
// Unfortunately this isn't straightforward since it the error_code classes use a number of
// incompatible singletons.
//
// To accomplish this we dynamically create a shim for every boost error category that passes
// the std::error_category calls on to the appropriate boost::system::error_category calls.
//==================================================================================================
#include <boost/system/error_code.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/once.hpp>
#include <boost/thread/locks.hpp>
#include <system_error>
namespace
{
// This class passes the std::error_category functions through to the
// boost::system::error_category object.
class BoostErrorCategoryShim : public std::error_category
{
public:
BoostErrorCategoryShim( const boost::system::error_category& in_boostErrorCategory )
:m_boostErrorCategory(in_boostErrorCategory), m_name(std::string("boost.") + in_boostErrorCategory.name()) {}
virtual const char *name() const;
virtual std::string message(value_type in_errorValue) const;
virtual std::error_condition default_error_condition(value_type in_errorValue) const;
private:
// The target boost error category.
const boost::system::error_category& m_boostErrorCategory;
// The modified name of the error category.
const std::string m_name;
};
// A converter class that maintains a mapping between a boost::system::error_category and a
// std::error_category.
class BoostErrorCodeConverter
{
public:
const std::error_category& GetErrorCategory( const boost::system::error_category& in_boostErrorCategory )
{
boost::lock_guard<boost::mutex> lock(m_mutex);
// Check if we already have an entry for this error category, if so we return it directly.
ConversionMapType::iterator stdErrorCategoryIt = m_conversionMap.find(&in_boostErrorCategory);
if( stdErrorCategoryIt != m_conversionMap.end() )
return *stdErrorCategoryIt->second;
// We don't have an entry for this error category, create one and add it to the map.
const std::pair<ConversionMapType::iterator, bool> insertResult = m_conversionMap.insert(
ConversionMapType::value_type(
&in_boostErrorCategory,
std::unique_ptr<const BoostErrorCategoryShim>(new BoostErrorCategoryShim(in_boostErrorCategory))) );
// Return the newly created category.
return *insertResult.first->second;
}
private:
// We keep a mapping of boost::system::error_category to our error category shims. The
// error categories are implemented as singletons so there should be relatively few of
// these.
typedef std::unordered_map<const boost::system::error_category*, std::unique_ptr<const BoostErrorCategoryShim>> ConversionMapType;
ConversionMapType m_conversionMap;
// This is accessed globally so we must manage access.
boost::mutex m_mutex;
};
namespace Private
{
// The init flag.
boost::once_flag g_onceFlag = BOOST_ONCE_INIT;
// The pointer to the converter, set in CreateOnce.
BoostErrorCodeConverter* g_converter = nullptr;
// Create the log target manager.
void CreateBoostErrorCodeConverterOnce()
{
static BoostErrorCodeConverter converter;
g_converter = &converter;
}
}
// Get the log target manager.
BoostErrorCodeConverter& GetBoostErrorCodeConverter()
{
boost::call_once( Private::g_onceFlag, &Private::CreateBoostErrorCodeConverterOnce );
return *Private::g_converter;
}
const std::error_category& GetConvertedErrorCategory( const boost::system::error_category& in_errorCategory )
{
// If we're accessing boost::system::generic_category() or boost::system::system_category()
// then just convert to the std::error_code versions.
if( in_errorCategory == boost::system::generic_category() )
return std::generic_category();
// I thought this should work, but at least in VC++10 std::error_category interprets the
// errors as generic instead of system errors. This means an error returned by
// GetLastError() like 5 (access denied) gets interpreted incorrectly as IO error.
//if( in_errorCategory == boost::system::system_category() )
// return std::system_category();
// The error_category was not one of the standard boost error categories, use a converter.
return GetBoostErrorCodeConverter().GetErrorCategory(in_errorCategory);
}
// BoostErrorCategoryShim implementation.
const char* BoostErrorCategoryShim::name() const
{
return m_name.c_str();
}
std::string BoostErrorCategoryShim::message(value_type in_errorValue) const
{
return m_boostErrorCategory.message(in_errorValue);
}
std::error_condition BoostErrorCategoryShim::default_error_condition(value_type in_errorValue) const
{
const boost::system::error_condition boostErrorCondition = m_boostErrorCategory.default_error_condition(in_errorValue);
// We have to convert the error category here since it may not have the same category as
// in_errorValue.
return std::error_condition( boostErrorCondition.value(), GetConvertedErrorCategory(boostErrorCondition.category()) );
}
}
std::error_code BoostToErrorCode( boost::system::error_code in_errorCode )
{
return std::error_code( in_errorCode.value(), GetConvertedErrorCategory(in_errorCode.category()) );
}
我适于上述溶液成一个较短的溶液。 使用thread_local的std ::地图,所以不需要锁定类别名称之间映射到它的实例。
该限制是你不能在线程之间传递的错误代码,因为类指针会有所不同。(将其转换为锁定功能很简单,如果你不希望使用thread_local存储)
此外,我给它更紧凑。
#include <iostream>
#include <map>
#include <boost/system/system_error.hpp>
namespace std
{
error_code make_error_code(boost::system::error_code error)
{
struct CategoryAdapter : public error_category
{
CategoryAdapter(const boost::system::error_category& category)
: m_category(category)
{
}
const char* name() const noexcept
{
return m_category.name();
}
std::string message(int ev) const
{
return m_category.message(ev);
}
private:
const boost::system::error_category& m_category;
};
static thread_local map<std::string, CategoryAdapter> nameToCategory;
auto result = nameToCategory.emplace(error.category().name(), error.category());
auto& category = result.first->second;
return error_code(error.value(), category);
}
};
int main() {
auto a = boost::system::errc::make_error_code(boost::system::errc::address_family_not_supported);
auto b = std::make_error_code(a);
std::cout << b.message() << std::endl;
}