2

这个简单的代码

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每个元素的宽度和精度等于当前值的 a,允许类似的代码

some_array_type<double> x;
std::cout << std::setw(12) << std::setprecision(8) << x << std::endl;

但是,正如 clang 所指出的,and () 返回的ostream::width()类型ostream::precision()与操纵器和( )std::size_t接受的参数类型不同,因此上面的代码会触发两个警告。std::setwstd::setprecisionint

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

4

1 回答 1

3

首先,这显然是实施中的错误。标准说std::ios_base::widthand std::ios_base::precisionuse 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(包括第一个元素)。至少在理论上;我不确定这对数组类型有多大用处(我当然不会坚持这样做,只要修改后的语义有据可查)。当然,精度是有粘性的。您不必为每个值设置它。(另一方面,用户应该记住并恢复它。)

于 2015-03-21T11:20:46.620 回答