std :: setw()和ostream :: width()之间的类型不一致

时间:2015-03-21 10:47:02

标签: c++ iostream iomanip

这个简单的代码

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 ++实现的错误)?

1 个答案:

答案 0 :(得分:3)

首先,它在实施中显然是一个错误。标准说 std::ios_base::widthstd::ios_base::precision使用{。}} std::streamsize,必须是“已签名的基础 积分类型“ - 在现代系统中,我希望long long,或可能longstd::size_t必须是未签名的, 并且可以说不是&#34;基本积分类型&#34;要么(虽然它可能是 一个typedef)。

事实仍然是成员函数std::ios_base::widthstd::ios_base::precision可能(也可能)使用不同的类型 比操纵者(总是int)。而如果 std::streamsize long longint,它的价值不会是int 适合auto。实际发生这种值的概率 正确的代码对我来说似乎很小,我会坚持 int(而不是与assert混淆),而不担心风险 溢出。或者,我使用w / x.size() - 1,但之前使用{{1}} 确保没有溢出。

最后:通常,宽度是元素的总宽度。所以 你应该设置的宽度是{{1}}(包括 第一个元素)。至少在理论上;我不确定它有多大用处 数组类型(我当然不会坚持它,只要有 修改后的语义已有详细记载)。当然,精确度是 黏;你不必为每个值设置它。 (另一方面, 用户应该记住并恢复它。)