【问题标题】:type inconsistency between std::setw() and ostream::width()std::setw() 和 ostream::width() 之间的类型不一致
【发布时间】:2015-03-21 10:47:02
【问题描述】:

这个简单的代码

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::setwstd::setprecision (int) 接受的参数类型不同,因此上面的代码触发了两个警告。

这种不一致是否有特殊原因,或者这只是 C++ 标准中的一个小缺陷(或 libc++ 实现的错误)?

【问题讨论】:

    标签: c++ iostream iomanip


    【解决方案1】:

    首先,这显然是实施中的错误。标准说 std::ios_base::widthstd::ios_base::precision 使用 std::streamsize,必须是“签名基本 整数类型”——在现代系统上,我希望long long,或者可能是longstd::size_t 必须是未签名的, 并且可以说也不是“基本整数类型”(尽管它可能是 一个类型定义)。

    事实上,成员函数std::ios_base::widthstd::ios_base::precision 可能(并且可能确实)使用不同的类型 比操纵器(总是int)。而如果 std::streamsizelong long,它的值不会 适合int。这种值实际出现在 正确的代码对我来说似乎很小,我会坚持使用 int(不要和auto混淆),不用担心风险 溢出。或者,我会使用int,但之前使用assert,以 确保没有溢出。

    最后:通常,宽度是元素的总宽度。所以 您应该设置的宽度是w / x.size() - 1(包括 第一个元素)。至少在理论上;我不确定这对我有多大用处 数组类型(我当然不会坚持,只要 修改后的语义有据可查)。当然,精度是 黏;您不必为每个值设置它。 (另一方面, 用户应该记住并恢复它。)

    【讨论】:

      猜你喜欢
      • 2017-12-19
      • 2018-09-24
      • 2020-07-20
      • 2013-07-28
      • 2022-08-04
      • 1970-01-01
      • 1970-01-01
      • 2012-11-08
      • 2019-04-20
      相关资源
      最近更新 更多