这个简单的代码
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
和{{1}接受的参数类型不同} {(std::setprecision
),这样上面的代码会触发两个警告。
是否存在这种不一致的特殊原因,或者这只是C ++标准中的一个小缺陷(或者是libc ++实现的错误)?
答案 0 :(得分:3)
首先,它在实施中显然是一个错误。标准说
std::ios_base::width
和std::ios_base::precision
使用{。}}
std::streamsize
,必须是“已签名的基础
积分类型“ - 在现代系统中,我希望long long
,或可能long
。 std::size_t
必须是未签名的,
并且可以说不是&#34;基本积分类型&#34;要么(虽然它可能是
一个typedef)。
事实仍然是成员函数std::ios_base::width
和
std::ios_base::precision
可能(也可能)使用不同的类型
比操纵者(总是int
)。而如果
std::streamsize
long long
是int
,它的价值不会是int
适合auto
。实际发生这种值的概率
正确的代码对我来说似乎很小,我会坚持
int
(而不是与assert
混淆),而不担心风险
溢出。或者,我使用w / x.size() - 1
,但之前使用{{1}}
确保没有溢出。
最后:通常,宽度是元素的总宽度。所以 你应该设置的宽度是{{1}}(包括 第一个元素)。至少在理论上;我不确定它有多大用处 数组类型(我当然不会坚持它,只要有 修改后的语义已有详细记载)。当然,精确度是 黏;你不必为每个值设置它。 (另一方面, 用户应该记住并恢复它。)