的文档std::numeric_limits<T>
说它不应该专门用于非基本类型。类似数字的用户定义类型呢?如果我定义自己的类型T
来表示数值并重载数字运算符,并且由 表示的信息对此numeric_limits
有意义 - 如果我专门numeric_limits
研究该类型,会有什么问题吗?
3 回答
简短的回答:
去吧,不会有什么不好的事情发生。
长答案:
C++ 标准广泛保护::std
C++11 17.6.4.2.1 中的命名空间,但在第 1 段和第 2 段中特别允许您的情况:
如果 C++ 程序将声明或定义添加到命名空间 std 或命名空间 std 内的命名空间,则 C++ 程序的行为是未定义的,除非另有说明。只有当声明依赖于用户定义的类型并且特化满足原始模板的标准库要求并且没有明确禁止时,程序才能将任何标准库模板的模板特化添加到命名空间 std。
[...]只有当声明依赖于用户定义类型的名称并且实例化满足原始模板的标准库要求时,程序才能显式实例化标准库中定义的模板。
较旧的 C++03 在 17.4.3.1/1 中有类似的定义:
除非另有说明,否则 C++ 程序将声明或定义添加到命名空间 std 或命名空间 std 内的命名空间是未定义的。程序可以将任何标准库模板的模板特化添加到命名空间 std。标准库模板的这种特化(完全或部分)会导致未定义的行为,除非声明依赖于用户定义的外部链接名称,并且除非特化满足原始模板的标准库要求。
在通过这个基本的垫脚石之后,您已经指出,C++03 18.2.1/4 禁止::std::numeric_limits
对某些类型进行专门化:
非基本标准类型,例如复杂(26.2.2),不应有专门化。
最新的 C++11 18.3.2.1/4 的措辞略有不同:
非算术标准类型,例如
complex<T>
(26.4.2),不应有特化。
但是,这两种公式都允许对非标准类型进行专门化,T
也就是说,因为您自己定义了它(正如@BoPersson 已经在评论中指出的那样)。
注意事项
C++11 18.3.2.3/1 提示您应该(但不要求您)确保您的专业化拥有所有成员。
此外,您可能希望确保您的专业化不违反 C++11 18.3.2.3/2:
在 cv 限定类型 cv T 上的 numeric_limits 特化的每个成员的值应等于在非限定类型 T 上特化的相应成员的值。
这实质上意味着,如果您希望将其专门用于T
,您也应该这样做T const
,T volatile
和T const volatile
。
只是一个例子:
namespace std {
template<> class numeric_limits<Temperature> {
public:
static Temperature lowest() {return Temperature(-273.15f);};
// One can implement other methods if needed
};
}
您可能不会将 std::numeric_limits 专门用于用户定义的类型。用户定义类型不是算术类型。C++ 标准中有明确的规定
1 numeric_limits 类模板为 C++ 程序提供了有关实现的算术类型表示的各种属性的信息。
例如
4 非算术标准类型,例如复数(26.4.2),不应有特化。