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

标签 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::setwstd::set precision (int) 接受的参数类型不同,例如上面代码触发两个警告。

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

最佳答案

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

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

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

关于c++ - std::setw() 和 ostream::width() 之间的类型不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29181808/

相关文章:

c++ - ofstream(mode ios::out) 在系统停止时删除现有文件空白

用于十六进制整数的 C++ 自定义 I/O 操纵器

c++ - 从 C++ 列表中删除对象

c++ - 如何使用qt将数据插入sqlite

c++ - 将二进制数据 (std::string) 写入 std::ofstream?

c++ - 如何将数字数据读取为 uint8_t

C++ 如何格式化包含可变整数的文本行,使其在给定宽度内右对齐?

c++ - 如何在 C++ 中使用 cout 打印整数值而不在逗号后添加零?

c++ - 为什么 2^80 字节的内存分配不会失败?

c++ - 两个类之间的共享方法