代码之家  ›  专栏  ›  技术社区  ›  Walter

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

  •  2
  • Walter  · 技术社区  · 11 年前

    这个简单的代码

    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 std::setprecision ( int ),使得上述代码触发两个警告。

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

    1 回复  |  直到 11 年前
        1
  •  3
  •   James Kanze    11 年前

    首先,这显然是实现中的一个错误。标准上说 那个 std::ios_base::width std::ios_base::precision 使用 std::streamsize ,必须是“已签名的基本 在现代系统中,我希望 long long ,或可能 long . std::size_t 需要无符号, 并且可以说也不是“基本积分型”(尽管它可能是 一个是typedef)。

    事实仍然是,成员发挥作用 std::ios_base::width std::ios_base::精度 可能(也可能)使用不同的类型 而不是操纵器( int ). 如果 std::streamsize 长-长 ,会有一些价值观 适合 整数 。此类值实际发生在 正确的代码对我来说似乎很小,我只能坚持下去 整数 (不要混淆 auto ),不必担心 溢流或者,我会使用 整数 ,但使用 assert 之前,到 确保没有溢出。

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