C++ 哪些 iomanip 操纵器是“粘性的”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1532640/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Which iomanip manipulators are 'sticky'?
提问by John K
I recently had a problem creating a stringstreamdue 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.
我最近在创建 a 时遇到了问题stringstream,因为我错误地认为std::setw()会影响每次插入的字符串流,直到我明确更改它。但是,插入后始终未设置。
// 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.
- 为什么是
setw()这样? - 有其他操纵者这样吗?
- 是否有之间的行为差异
std::ios_base::width()和std::setw()? - 最后是否有一个在线参考资料清楚地记录了这种行为?我的供应商文档(MS Visual Studio 2005)似乎没有清楚地显示这一点。
采纳答案by Martin York
Important notes from the comments below:
以下评论中的重要说明:
By Martin:
马丁:
@Chareles: Then by this requirement all manipulators are sticky. Except setw which seems to be reset after use.
@Chareles:那么根据这个要求,所有操纵器都是粘性的。除了 setw 似乎在使用后重置。
By Charles:
查尔斯:
Exactly! and the only reason that setw appears to behave differently is because there are requirements on formatted output operations to explicitly .width(0) the output stream.
确切地!并且 setw 似乎表现不同的唯一原因是因为对格式化输出操作有要求以显式 .width(0) 输出流。
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:
查看代码,以下操作符返回一个对象而不是一个流:
setiosflags
resetiosflags
setbase
setfill
setprecision
setw
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 setware sticky.
这是将操作仅应用于应用于流的下一个对象的常用技术。不幸的是,这并不排除它们具有粘性。测试表明,除了setw粘性之外,所有这些都是粘性的。
setiosflags: Sticky
resetiosflags:Sticky
setbase: Sticky
setfill: Sticky
setprecision: 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 Stickymanipulators.
所有其他操纵器都返回一个流对象。因此,它们更改的任何状态信息都必须记录在流对象中,因此是永久的(直到另一个操纵器更改状态)。因此,以下操纵器必须是粘性操纵器。
[no]boolalpha
[no]showbase
[no]showpoint
[no]showpos
[no]skipws
[no]unitbuf
[no]uppercase
dec/ hex/ oct
fixed/ scientific
internal/ left/ right
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.
这些操纵器实际上对流本身而不是流对象执行操作(尽管从技术上讲流是流对象状态的一部分)。但我不相信它们会影响流对象状态的任何其他部分。
ws/ endl/ ends/ flush
The conclusion is that setw seems to be the only manipulator on my version that is not sticky.
结论是 setw 似乎是我的版本上唯一不粘的操纵器。
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:
对于查尔斯来说,一个只影响链中下一项的简单技巧:
这是一个如何使用对象临时更改状态然后通过使用对象将其恢复的示例:
#include <iostream>
#include <iomanip>
// Private object constructed by the format object PutSquareBracket
struct SquareBracktAroundNextItem
{
SquareBracktAroundNextItem(std::ostream& str)
:m_str(str)
{}
std::ostream& m_str;
};
// New Format Object
struct PutSquareBracket
{};
// Format object passed to stream.
// All it does is return an object that can maintain state away from the
// stream object (so that it is not STICKY)
SquareBracktAroundNextItem operator<<(std::ostream& str,PutSquareBracket const& data)
{
return SquareBracktAroundNextItem(str);
}
// The Non Sticky formatting.
// Here we temporariy set formating to fixed with a precision of 10.
// After the next value is printed we return the stream to the original state
// Then return the stream for normal processing.
template<typename T>
std::ostream& operator<<(SquareBracktAroundNextItem const& bracket,T const& data)
{
std::ios_base::fmtflags flags = bracket.m_str.flags();
std::streamsize currentPrecision = bracket.m_str.precision();
bracket.m_str << '[' << std::fixed << std::setprecision(10) << data << std::setprecision(currentPrecision) << ']';
bracket.m_str.flags(flags);
return bracket.m_str;
}
int main()
{
std::cout << 5.34 << "\n" // Before
<< PutSquareBracket() << 5.34 << "\n" // Temp change settings.
<< 5.34 << "\n"; // After
}
> ./a.out
5.34
[5.3400000000]
5.34
回答by CB Bailey
The reason that widthdoes not appear to be 'sticky' is that certain operations are guaranteed to call .width(0)on an output stream. Those are:
其原因width并不显得“粘性”是某些操作,保证通话.width(0)的输出流。那些是:
21.3.7.9 [lib.string.io]:
21.3.7.9 [lib.string.io]:
template<class charT, class traits, class Allocator>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& os,
const basic_string<charT,traits,Allocator>& str);
22.2.2.2.2 [lib.facet.num.put.virtuals]: All do_putoverloads for the num_puttemplate. These are used by overloads of operator<<taking a basic_ostreamand a built in numeric type.
22.2.2.2.2 [lib.facet.num.put.virtuals]:模板的所有do_put重载num_put。这些由operator<<采用 abasic_ostream和内置数字类型的重载使用。
22.2.6.2.2 [lib.locale.money.put.virtuals]: All do_putoverloads for the money_puttemplate.
22.2.6.2.2 [lib.locale.money.put.virtuals]:模板的所有do_put重载money_put。
27.6.2.5.4 [lib.ostream.inserters.character]: Overloads of operator<<taking a basic_ostreamand one of the char type of the basic_ostream instantiation or char, signed charor unsigned charor pointers to arrays of these char types.
27.6.2.5.4 [lib.ostream.inserters.character]:重载operator<<abasic_ostream和 basic_ostream 实例化的 char 类型之一,或char,signed charorunsigned char或指向这些 char 类型数组的指针。
To be honest I'm not sure of the rationale for this, but no other states of an ostreamshould be reset by formatted output functions. Of course, things like badbitand failbitmay be set if there is a failure in the output operation, but that should be expected.
老实说,我不确定这样做的理由,但是ostream格式化的输出函数不应该重置 a 的其他状态。当然,如果输出操作失败badbit,failbit可能会设置和 之类的东西,但这应该是意料之中的。
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.
例如
std::cout << std::setw(6) << 4.5 << '|' << 3.6 << '\n';
" 4.5 | 3.6 \n"
To 'correct' this would take:
要“纠正”这将需要:
std::cout << std::setw(6) << 4.5 << std::setw(0) << '|' << std::setw(6) << 3.6 << std::setw(0) << '\n';
whereas with a resetting width, the desired output can be generated with the shorter:
而使用重置宽度,可以使用较短的输出生成所需的输出:
std::cout << std::setw(6) << 4.5 << '|' << std::setw(6) << 3.6 << '\n';
回答by David Brown
setw()only affects the next insertion. That's just the way setw()behaves. The behavior of setw()is the same as ios_base::width(). I got my setw()information from cplusplus.com.
setw()只影响下一次插入。这就是setw()行为方式。的行为setw()与 相同ios_base::width()。我setw()从cplusplus.com获得了我的信息。
You can find a full list of manipulators here. From that link, all the stream flags should say set until changed by another manipulator. One note about the left, rightand internalmanipulators: They are like the other flags and dopersist 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 example
您可以在此处找到完整的操纵器列表。从该链接开始,所有流标志都应该设置,直到被另一个操纵器更改。关于left,right和internal操纵器的一个注意事项:它们就像其他标志一样,并且会一直存在,直到更改为止。但是,它们只有在设置了流的宽度时才有效,并且必须每行设置宽度。所以,例如
cout.width(6);
cout << right << "a" << endl;
cout.width(6);
cout << "b" << endl;
cout.width(6);
cout << "c" << endl;
would give you
会给你
> a
> b
> c
but
但
cout.width(6);
cout << right << "a" << endl;
cout << "b" << endl;
cout << "c" << endl;
would give you
会给你
> a
>b
>c
The Input and Output manipulators are not sticky and only occur once where they are used. The parametrized manipulators are each different, here's a brief description of each:
输入和输出操纵器不具有粘性,仅在使用它们的地方出现一次。参数化的操纵器各不相同,以下是每个操纵器的简要说明:
setiosflagslets you manually set flags, a list of which can be fount here, so it is sticky.
setiosflags允许您手动设置标志,可以在此处找到其列表,因此它很粘。
resetiosflagsbehaves the similar to setiosflagsexcept it unsets the specified flags.
resetiosflags行为类似于,setiosflags除了它取消设置指定的标志。
setbasesets the base of integers inserted into the stream (so 17 in base 16 would be "11", and in base 2 would be "10001").
setbase设置插入流中的整数的基数(因此基数 16 中的 17 将是“11”,基数 2 中的将是“10001”)。
setfillsets the fill character to insert in the stream when setwis used.
setfill设置填充字符以在使用时插入到流中setw。
setprecisionsets the decimal precision to be used when inserting floating point values.
setprecision设置插入浮点值时要使用的小数精度。
setwmakes only the next insertion the specified width by filling with the character specified in setfill

