我正在尝试创建自己的基于枚举的错误类别,并希望在某些命名空间中定义带有错误代码的枚举。令我惊讶的是,这阻止了我的枚举值自动转换为std::error_code
(如果在全局命名空间中定义了枚举,则此类转换有效)。
#include <system_error>
namespace NS { enum class X {a,b,c}; }
using NS::X;
class X_category : public std::error_category
{
public:
virtual const char *name() const noexcept override { return "X"; }
virtual std::string message(int ev) const override { return ""; }
};
inline const std::error_category& X_category()
{
static class X_category c; return c;
}
template<> struct std::is_error_code_enum<X> : public std::true_type{};
inline std::error_code make_error_code(X result)
{
return std::error_code(static_cast<int>(result), X_category());
}
int main()
{
std::error_code e = X::a; // does not work !!
}
我在上面的代码中遗漏了某些内容(可能与重载决策规则有关),以使其有效吗?或者std::is_error_code_enum<>
的枚举只能在全局命名空间中定义吗?
EDIT。我的编译器(MSVC2013)没有抱怨它,但它似乎是std :: is_error_code_enum&lt;&gt;的特化。必须在std命名空间内完成。我还在name()方法上添加了noexcept关键字,以使代码更符合C ++ 11(MSVC2013不会理解noexcept,但MSVC2015会这样做。)
EDIT2。根据C ++ 11 14.7.3.2 [temp.expl.spec]:
应在包含专用模板的命名空间中声明显式特化。
因此没有必要对std :: is_error_code_enum&lt;&gt;进行专门化。在std命名空间内。 MSVC正确编译它,但是GCC抱怨这实际上是GCC中的一个错误,因为GCC的行为是旧的C ++ 03规则,这些规则更具限制性。
答案 0 :(得分:2)
error_code
中的构造函数模板确实被认为是在重载决策中 - 您正确地专注于is_error_code
。问题是error_code
构造函数模板定义中此行中的ADL:
*this = make_error_code(__e);
ADL不考虑全局命名空间,因为X
仅在NS
中定义,而不是全局命名空间。 [basic.lookup.argdep] /(2.3):
如果
T
是枚举类型,则其关联的命名空间是 其声明的最内部封闭命名空间。 [..]
使用声明不会改变这一点。 [basic.lookup.argdep] / 2:
命名空间和类的集合完全由类型决定 函数参数(以及任何模板模板的命名空间) 参数)。 用于指定类型的Typedef名称和 using-declaration
要解决此问题,请将您的make_error_code
添加到NS:
namespace NS {
inline std::error_code make_error_code(X result)
{
return std::error_code(static_cast<int>(result), X_category());
}
}
答案 1 :(得分:1)
我认为问题是大多数设置代码都需要在命名空间内。这段代码在ideone中为我编译和运行:
#include <system_error>
#include <iostream>
namespace NS {
enum X {a,b,c};
class X_category : public std::error_category
{
public:
virtual const char *name() const noexcept override { return "X"; }
virtual std::string message(int ev) const override { return "M"; }
};
inline std::error_code make_error_code(X result)
{
return std::error_code(static_cast<int>(result), X_category());
}
}
namespace std {
template<> struct is_error_code_enum<NS::X> : public true_type{};
}
int main()
{
std::cout << NS::X::a;
std::error_code e = NS::X::a;
std::cout << e.value();
}
不幸的是,我仍然无法理解system_error,所以我无法解释为什么,例如,使用枚举类而不仅仅是简单的枚举给我一个未指定的运行时错误。