这个简单的代码
template<typename T>
std::ostream&operator<<(std::ostream&s, some_array_type<T> const&x)
{
auto w = s.width();
auto p = s.precision();
s << x[0];
for(std::size_t i=1; i!=x.size(); ++i)
s << ' ' << std::setw(w) << std::setprecision(p) << m[i];
return s;
}
打算打印一个some_array_type
,其中每个元素的宽度和精度等于当前值,允许像这样的代码
some_array_type<double> x;
std::cout << std::setw(12) << std::setprecision(8) << x << std::endl;
但是,正如 clang 指出的那样,ostream::width()
和 ostream::precision()
返回的类型 (std::size_t
) 与操纵器 std::setw
和 std::set precision
(int
) 接受的参数类型不同,例如上面代码触发两个警告。
这种不一致是否有特殊原因,或者这只是 C++ 标准中的一个小缺陷(或 libc++ 实现的错误)?
最佳答案
首先,这显然是实现中的一个错误。标准说
std::ios_base::width
和 std::ios_base::precision
使用
std::streamsize
,它需要是“签名的基本
整数类型”——在现代系统上,我期望 long long
,或者可能是 long
。 std::size_t
需要无符号,
并且可以说也不是“基本整数类型”(尽管它可能是
typedef 之一)。
事实上,成员函数 std::ios_base::width
和
std::ios_base::precision
可能(并且可能确实)使用不同的类型
比操纵器(始终是int
)。而如果
std::streamsize
是 long long
,它的值不会
适合 int
。该值实际出现的概率
正确的代码对我来说似乎很小,我会坚持使用
int
(并且不与 auto
混淆),并且不用担心风险
溢出。或者,我会使用 int
,但之前加上 assert
来
确保没有溢出。
最后:通常情况下,宽度是元素的总宽度。所以
您应该设置的宽度是 w/x.size() - 1
(包括
第一个元素)。至少在理论上是这样;我不确定这有多大用处
数组类型(我当然不会坚持这样做,只要
修改后的语义有详细记录)。当然,精度是
黏;您不必为每个值都设置它。 (另一方面,
用户应该记住并恢复它。)
关于c++ - std::setw() 和 ostream::width() 之间的类型不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29181808/