为什么在流中插入会使其宽度重置为 0

Why an insertion in streams makes its width reset to 0?

本文关键字:插入 为什么      更新时间:2023-10-16

似乎插入会导致流将其宽度重置为 0。换句话说,每当你想要对齐输出时,你都需要重复调用width(),这让我想知道为什么。我查看了 c++11 标准,我找到了部分答案,这表明 width(0) 根据 ISO C++ 标准 §27.7.3.6.4.1 在字符插入器中调用。但是,它们只是机械臂的一个子集,这不是一个完整的答案。那么,算术机械臂呢?我找不到任何其他可以解释流行为的参考资料。

因为这是指定流的方式。 在<<运算符中, width应重置,其他格式选项没有。 我只能猜测为什么:大概,对于以下情况:

std::cout << std::setw(8) << someValue << " cm";

例如,您不希望宽度应用于字符串" cm"。但是您希望能够编写:

std::cout << std::setw(8) << price << " | " << setw(20) << article;

其中article是一个字符串。

当然,除此之外,要使其正常工作,您还必须更改字符串前的对齐方式,并且对齐方式的更改将具有粘性,影响下一个数字输出。

当然,在实践中,有经验的程序员不会写这种法典。 他们会使用类似的东西:

std::cout << price(column1Width) << article.price
    << " | " << label(column2Width) << article.name;

(假设他们仍然必须使用固定宽度生成表字体)。 其中pricelabel是设置任何数字的操纵者格式标志,并在其析构函数中恢复它们。 (因为它们是临时的,他们的析构函数将在完整结束时调用表达式。 这样,这行特定的代码就不会说任何关于物理格式的信息,而是第一个值应格式化为价格,第二个格式应为标签。 (和当然,如果更高层的人后来决定价格或标签应该格式不同,您只需更改操纵器,而不是搜索所有输出语句,并尝试找出哪个是价格,哪些不是。

编辑(添加了对标准的引用):

重要的是要注意,该标准不能涵盖这里的所有内容,由于大多数时候,您将使用自定义operator<<,由要输出的类的作者。 大多数内置 §22.4.2.2.2 在阶段 3 的描述中涵盖了operator<<

如果str.width()为非零,并且序列中的字符数 在第 2 阶段小于 str.width() 之后,则有足够的填充字符 添加到序列中指示的填充位置,以带来 序列的长度str.width()

str.width(0)被称为。

对于字符和 C 样式字符串,这是指定的(在大致相同的中方式)在 §27.7.3.6.4 中。 有关std::string,请参见 §21.4.8.8。

对于std::complex:该标准根据其他术语定义插入插入运算符。 因此,任何width设置都只会影响真实元素。 (实际上,我认为我们可以考虑这一点破碎。 当我实现一个预标准复杂类时,我的<<检查宽度,如果它不为零,则减去 3 作为非数字字段,然后除以 2 并在输出每个字段之前设置它双。 我不确定这是否正确,但它肯定比标准规定的内容。 我还使用分号作为分隔符如果小数点是逗号,就像我住过的大多数地方一样。

其他格式选项保持不变的事实是因为该标准没有指定任何内容,以及其他副作用,除指定者外,假定为禁止。

在所有情况下,规范都说调用stream.width(0)。但在标准中,每种情况都是单独指定的。 没有我能找到的任何一般规则的规范(即使是意图)。然而,传统上,规则一直是:重置宽度,然后离开其他不变。 最小惊喜原则说你也应该为用户定义的<<(和>>)执行此操作。