哪些 iomanip 操纵器是“粘性的”?
我最近在创建 stringstream
时遇到了问题,因为我错误地认为 std::setw()
会影响每次插入的 stringstream,直到我显式更改它。然而,插入后它总是被取消设置。
// With timestruct with value of 'Oct 7 9:04 AM'
std::stringstream ss;
ss.fill('0'); ss.setf(ios::right, ios::adjustfield);
ss << setw(2) << timestruct.tm_mday;
ss << timestruct.tm_hour;
ss << timestruct.tm_min;
std::string filingTime = ss.str(); // BAD: '0794'
所以,我有很多问题:
- 为什么
setw()
是这样的? - 其他操纵者也是这样吗?
std::ios_base::width()
和std::setw()
之间的行为是否存在差异?- 最后是否有在线参考资料清楚地记录了这种行为?我的供应商文档(MS Visual Studio 2005)似乎没有清楚地表明这一点。
I recently had a problem creating a stringstream
due to the fact that I incorrectly assumed std::setw()
would affect the stringstream for every insertion, until I changed it explicitly. However, it is always unset after the insertion.
// With timestruct with value of 'Oct 7 9:04 AM'
std::stringstream ss;
ss.fill('0'); ss.setf(ios::right, ios::adjustfield);
ss << setw(2) << timestruct.tm_mday;
ss << timestruct.tm_hour;
ss << timestruct.tm_min;
std::string filingTime = ss.str(); // BAD: '0794'
So, I have a number of questions:
- Why is
setw()
this way? - Are any other manipulators this way?
- Is there a difference in behavior between
std::ios_base::width()
andstd::setw()
? - Finally is there an online reference that clearly documents this behavior? My vendor documentation (MS Visual Studio 2005) doesn't seem to clearly show this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
以下评论中的重要说明:
马丁:
查尔斯:
以下是得出上述结论的讨论:
查看代码,以下操纵器返回一个对象而不是流:
这是一种仅将操作应用于应用于流的下一个对象的常见技术。不幸的是,这并不妨碍它们具有粘性。测试表明,除了
setw
之外,所有这些都是粘性的。所有其他操纵器返回一个流对象。因此,它们更改的任何状态信息都必须记录在流对象中,因此是永久性的(直到另一个操纵器更改状态)。因此以下操纵器必须是粘性操纵器。
这些操纵器实际上对流本身而不是流对象执行操作(尽管从技术上讲,流是流对象状态的一部分)。但我不相信它们会影响流对象状态的任何其他部分。
结论是 setw 似乎是我的版本中唯一不粘的操纵器。
对于 Charles 来说,有一个简单的技巧,可以只影响链中的下一个项目:
以下是如何使用对象临时更改状态然后通过使用对象将其恢复的示例:
Important notes from the comments below:
By Martin:
By Charles:
The following is the discussion that lead to the above conclusion:
Looking at the code the following manipulators return an object rather than a stream:
This is a common technique to apply an operation to only the next object that is applied to the stream. Unfortunately this does not preclude them from being sticky. Tests indicate that all of them except
setw
are sticky.All the other manipulators return a stream object. Thus any state information they change must be recorded in the stream object and is thus permanent (until another manipulator changes the state). Thus the following manipulators must be Sticky manipulators.
These manipulators actually perform an operation on the stream itself rather than the stream object (Though technically the stream is part of the stream objects state). But I do not believe they affect any other part of the stream objects state.
The conclusion is that setw seems to be the only manipulator on my version that is not sticky.
For Charles a simple trick to affect only the next item in the chain:
Here is an Example how an object can be used to temporaily change the state then put it back by the use of an object:
width
看起来不“粘性”的原因是某些操作保证在输出流上调用.width(0)
。它们是:21.3.7.9 [lib.string.io]:
22.2.2.2.2 [lib.facet.num.put.virtuals]:
num_put
do_put 重载> 模板。这些由采用basic_ostream
和内置数字类型的operator<<
重载使用。22.2.6.2.2 [lib.locale.money.put.virtuals]:
money_put
模板的所有do_put
重载。27.6.2.5.4 [lib.ostream.inserters.character]:重载
operator<<
,采用basic_ostream
和 basic_ostream 实例化的 char 类型之一或 < code>char、signedchar
或unsigned char
或指向这些 char 类型数组的指针。老实说,我不确定这样做的理由,但
ostream
的其他状态不应通过格式化输出函数重置。当然,如果输出操作失败,则可能会设置诸如badbit
和failbit
之类的内容,但这应该是预料之中的。我能想到的重置宽度的唯一原因是,当尝试输出某些分隔字段时,如果分隔符被填充,这可能会令人惊讶。
例如,
要“纠正”这将需要:
而使用重置宽度,可以使用较短的值生成所需的输出:
The reason that
width
does not appear to be 'sticky' is that certain operations are guaranteed to call.width(0)
on an output stream. Those are:21.3.7.9 [lib.string.io]:
22.2.2.2.2 [lib.facet.num.put.virtuals]: All
do_put
overloads for thenum_put
template. These are used by overloads ofoperator<<
taking abasic_ostream
and a built in numeric type.22.2.6.2.2 [lib.locale.money.put.virtuals]: All
do_put
overloads for themoney_put
template.27.6.2.5.4 [lib.ostream.inserters.character]: Overloads of
operator<<
taking abasic_ostream
and one of the char type of the basic_ostream instantiation orchar
, signedchar
orunsigned char
or pointers to arrays of these char types.To be honest I'm not sure of the rationale for this, but no other states of an
ostream
should be reset by formatted output functions. Of course, things likebadbit
andfailbit
may be set if there is a failure in the output operation, but that should be expected.The only reason that I can think of for resetting the width is that it might be surprising if, when trying to output some delimited fields, your delimiters were padded.
E.g.
To 'correct' this would take:
whereas with a resetting width, the desired output can be generated with the shorter:
setw()
仅影响下一次插入。这就是setw()
的行为方式。setw()
的行为与ios_base::width()
相同。我从 cplusplus.com 获取了setw()
信息。您可以在此处找到操纵器的完整列表。从该链接开始,所有流标志都应保持设置状态,直到被另一个操纵器更改为止。关于
left
、right
和internal
操纵器的一点注意事项:它们与其他标志一样,并且do会一直持续到更改为止。然而,它们只有在设置了流的宽度时才有效,并且必须每行都设置宽度。因此,例如会给您
但
会给您
输入和输出操纵器不具有粘性,并且仅在使用它们时出现一次。参数化操纵器各不相同,以下是每个操纵器的简要说明:
setiosflags
允许您手动设置标志,可以在 找到标志列表这里,所以它是粘性的。
resetiosflags
的行为类似于setiosflags
除非它取消设置指定的标志。setbase
设置插入的整数的基数流(因此 17 在基数 16 中将是“11”,在基数 2 中将是“10001”)。setfill
设置要插入的填充字符使用setw
时的流。set precision
设置要使用的小数精度插入浮点值时。setw
仅使下一个插入指定通过填充setfill
setw()
only affects the next insertion. That's just the waysetw()
behaves. The behavior ofsetw()
is the same asios_base::width()
. I got mysetw()
information from cplusplus.com.You can find a full list of manipulators here. From that link, all the stream flags should stay set until changed by another manipulator. One note about the
left
,right
andinternal
manipulators: They are like the other flags and do persist until changed. However, they only have an effect when the width of the stream is set, and the width must be set every line. So, for examplewould give you
but
would give you
The Input and Output manipulators are not sticky and only occur once where they are used. The parameterized manipulators are each different, here's a brief description of each:
setiosflags
lets you manually set flags, a list of which can be found here, so it is sticky.resetiosflags
behaves similar tosetiosflags
except it unsets the specified flags.setbase
sets the base of integers inserted into the stream (so 17 in base 16 would be "11", and in base 2 would be "10001").setfill
sets the fill character to insert in the stream whensetw
is used.setprecision
sets the decimal precision to be used when inserting floating point values.setw
makes only the next insertion the specified width by filling with the character specified insetfill