0

所以挑战是用这个输出编写一个程序:

000042
420000
42
-42-

我的第一次尝试是这样的:

int fortyTwo = 42;

cout << setfill('0') << setw(6) << fortyTwo << endl;
cout << fortyTwo << setfill('0') << setw(6) << endl;
cout << fortyTwo << endl;
cout << setfill('-') << setw(4) << fortyTwo << setfill('-') << endl;

这给了我这样的东西:

000042
42
000042
42-- (sometimes just -42)

这是作者的解决方案:

cout << setfill('0') << setw(6) << 42 << endl;
cout << left << setw(6) << 42 << endl;
cout << 42 << endl;
cout << setfill('-') << setw(4) << -42 << endl;

为什么作者只使用一次setfill?setfill 如何在前两行工作,但在第 3 行突然停止?将 setfill('-') 和 setw(4) 放在 -42 之前如何产生 -42- 而不是--42?左对齐运算符需要什么?

最后为什么我的版本没有产生正确的输出?

4

3 回答 3

0

setw() 只影响下一个输出。其他所有问题几乎都是这种行为的结果。也就是说,除非您尝试扩大输出,否则不会发生填充字符或对齐。

于 2013-07-19T01:41:56.957 回答
0

std::setw仅确定下一个输出字段的宽度,但设置用于传递给它的流对象的所有std::setfill进一步打印操作的填充字符。

所以填充字符实际上并没有在输出的第三行突然停止工作。std::setw但是因为在生成输出之前没有操纵器,所以填充字符很简单,没有使用。

std::left,如std::setfill,在取消之前生效。所以,设置为第二行输出后,在生成第四行时仍然生效。由于在第四行中,填充字符是-,因此该字符被附加到行尾。(-开头是由于它被明确指定为输出字符串的一部分。)


引用标准 (C++11) 以供参考。

  1. std::setfill在 27.7.4/5 中描述:

    unspecified setfill(char_type c);

    返回: 未指定类型的对象,如果 out 是 basic_ostream 类型的对象并且 c 具有类型charT,则表达式的out << setfill(c)行为就好像它调用f(out, c)了 ,其中函数f定义为:

    template<class charT, class traits>
    void f(basic_ios<charT,traits>& str, charT c) {
        // set fill character
        str.fill(c);
    }
    

    表达式out << setfill(c)应具有 typebasic_ostream<charT, traits>&和 value out

    所以调用fill()流的函数,这又在 27.5.5.3/14 中描述:

    char_type fill(char_type fillch);
    后置条件:traits::eq(fillch, fill())

    换句话说,它修改了作为流特征一部分的属性。只需说特征在显式修改之前都是有效的(不仅适用于下一个输出字段)。

  2. 情况类似std::left,设置流的adjustfield参数,见27.5.6.2/3:

    ios_base& left(ios_base& str);
    效果:通话str.setf(ios_base::left, ios_base::adjustfield).

  3. std::setw另一方面,在 27.7.5/7 中描述

    未指定setw(int n);
    返回:未指定类型的对象,如果 out 是 的实例,basic_ostream<charT, traits>则表达式的out << setw(n)行为就像它被调用f(out, n),或者如果 in 是类型的对象,basic_istream<charT, traits>那么表达式的in >> setw(n)行为就像它被调用f(in, n),其中函数f定义为:

    void f(ios_base& str, int n) {
      // set width
      str.width(n);
    }
    

    表达式 out << setw(n) 应具有类型 basic_ostream& 和值 out。>> setw(n) 中的表达式应具有类型 basic_istream& 和值 in。

    实际上,该属性在格式化输出操作发生后被width重置。0例如,operator<<在应用于字符串时的描述中(即当您使用<<- 语法输出字符串时),27.7.3.6.4/5 中描述的操作顺序(强调我的):

    填充如 22.4.2.2.2 中所述确定。从 s 开始的 n 个字符使用out.widen(27.5.5.3) 加宽。将加宽的字符和任何所需的填充插入到 out 中。来电width(0)

    在数字类型 (27.7.3.6.2/1,2,3) 的格式化输出操作的情况下,std::num_put(这是一个std::locale::facet)模板用于将数字转换为字符串并打印它。22.4.2.2 详细描述了如何执行该操作,其最后一步(在输出字符串之后)将宽度重置为0(22.4.2.2.2/5,阶段 3,最后):

    str.width(0)叫做

对各种 IO 操纵器影响的进一步研究表明,实际上,std:setw它是唯一只对以下(格式化)输出操作起作用的操纵器。另请参阅哪些 iomanipulators 是“粘性的”?,尤其是 Charles Bailey 的回答,用于比较不同机械手的“粘性”。

于 2013-07-19T01:43:55.633 回答
0

setfill(与大多数ostream修饰符一样,例如hex, dec, left, 二进制修饰符,精度 IIRC )一旦更改它们就会保持它们的值。

让我稍微备份一下。

std::ostream(类cout是一个实例)具有内部格式值。内部变量告诉它填充字符是什么,是否以十六进制打印等。

除非您更改它们,否则这些值中的大多数(可能除了 之外的所有值width)都不会更改。因此,一旦您设置了fill,它就会一直保持这种状态,直到您将其更改为其他内容。

width是不同的(不幸的是:(我确定他们有他们的理由)。设置后,它只会保留在您编写的下一个项目中 - 然后它重置为 0。

您似乎错过的第二件事是widthand filletc. 不打印任何内容,它们只会更改内部状态,因此适用于它们之后的内容

因此,让我们分析您的解决方案:

您将 设置fill为 0,将 设置width为 6,打印 42 - 这是 2 个字符,因此通过添加四个 0-s 扩展为 6(在左侧,因为默认为右对齐文本)。现在你打印了一些东西,所以width重置(!)

现在你开始了一个新行(endl),打印 42(宽度被重置,所以它只是以任何宽度打印它,不需要填充!),设置fill为 0(它已经是!fill保持直到你改变它),将宽度设置为 6(但对于下一个值,而不是已经打印的值!)并换行。

现在你打印 42(width是 6,所以它用 0 填充所需的 4 个额外字符)(width打印后重置​​)并换行。

您将填充设置为 - 并将宽度设置为 4,并在左侧打印 42 - 通过添加两个扩展为 4 个字符(不像您写的那样......很奇怪),然后再次将填充设置为 - (不需要,也未使用,因为在那之后您不打印任何东西 -setfill其他格式只会影响它们之后发生的事情!)

于 2013-07-19T01:53:05.200 回答