我最近遇到了一个问题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'
所以,我有很多问题:
为什么setw()
这样?
有这样的其他操纵者吗?
是否有之间的行为差异std::ios_base::width()
和std::setw()
?
最后有一个在线参考,清楚地记录了这种行为?我的供应商文档(MS Visual Studio 2005)似乎没有清楚地显示这一点.
Martin York.. 84
以下评论的重要说明:
马丁:
@Chareles:然后通过这个要求,所有操纵器都是粘性的.除了在使用后似乎重置的setw.
查尔斯:
究竟!并且setw表现出不同行为的唯一原因是因为格式化输出操作需要显式地.width(0)输出流.
以下是导致上述结论的讨论:
查看代码,以下操纵器返回一个对象而不是一个流:
setiosflags resetiosflags setbase setfill setprecision setw
这是将操作仅应用于应用于流的下一个对象的常用技术.不幸的是,这并不妨碍它们变得粘稠.测试表明所有这些setw
都是粘性的.
setiosflags: Sticky resetiosflags:Sticky setbase: Sticky setfill: Sticky setprecision: Sticky
所有其他操纵器都返回一个流对象.因此,它们改变的任何状态信息必须记录在流对象中,因此是永久的(直到另一个操纵器改变状态).因此,以下操纵器必须是粘性操纵器.
[no]boolalpha [no]showbase [no]showpoint [no]showpos [no]skipws [no]unitbuf [no]uppercase dec/ hex/ oct fixed/ scientific internal/ left/ right
这些操纵器实际上对流本身而不是流对象执行操作(尽管从技术上讲,流是流对象状态的一部分).但我不相信它们会影响流对象状态的任何其他部分.
ws/ endl/ ends/ flush
结论是setw似乎是我的版本中唯一没有粘性的操纵器.
对于查尔斯来说,一个简单的技巧只能影响链中的下一个项目:
下面是一个示例如何使用对象临时更改状态,然后通过使用对象将其放回:
#include#include // 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 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
究竟!并且`setw`看起来表现不同的唯一原因是因为格式化输出操作需要显式地`.width(0)`输出流. (3认同)
返回流__Must__的对象是粘性的,而返回对象的对象可能是粘性的,但不是必需的.我将用约翰的信息更新答案. (2认同)
CB Bailey.. 30
其原因width
并不显得"粘性"是某些保证操作调用.width(0)
上的输出流.那些是:
21.3.7.9 [lib.string.io]:
templatebasic_ostream & operator<<(basic_ostream & os, const basic_string & str);
22.2.2.2.2 [lib.facet.num.put.virtuals]:模板的所有do_put
重载num_put
.这些用于operator<<
采用a basic_ostream
和内置数字类型的重载.
22.2.6.2.2 [lib.locale.money.put.virtuals]:模板的所有do_put
重载money_put
.
27.6.2.5.4 [lib.ostream.inserters.character]:的重载operator<<
服用basic_ostream
和焦炭类型basic_ostream实例化的一个或char
签署char
或unsigned char
或指针这些字符类型的数组.
说实话,我不确定这个的基本原理,但是没有其他状态ostream
应该通过格式化的输出函数重置.当然,如果输出操作出现故障,可以设置badbit
和failbit
设置,但这应该是预期的.
我可以想到重置宽度的唯一原因是,如果在尝试输出一些分隔字段时,您的分隔符被填充,这可能会令人惊讶.
例如
std::cout << std::setw(6) << 4.5 << '|' << 3.6 << '\n'; " 4.5 | 3.6 \n"
要"纠正",这需要:
std::cout << std::setw(6) << 4.5 << std::setw(0) << '|' << std::setw(6) << 3.6 << std::setw(0) << '\n';
而使用重置宽度,可以生成所需的输出更短的:
std::cout << std::setw(6) << 4.5 << '|' << std::setw(6) << 3.6 << '\n';
David Brown.. 6
setw()
仅影响下一次插入.这就是setw()
表现的方式.行为setw()
是一样的ios_base::width()
.我setw()
从cplusplus.com获取了我的信息.
您可以在此处找到完整的操纵器列表.从该链接开始,所有流标志应该设置为set,直到被另一个操纵器更改为止.一个说明有关left
,right
并internal
操纵:他们就像其他标志和你继续下去,直到改变.但是,它们仅在设置流的宽度时有效,并且必须在每一行设置宽度.所以,例如
cout.width(6); cout << right << "a" << endl; cout.width(6); cout << "b" << endl; cout.width(6); cout << "c" << endl;
会给你的
> a > b > c
但
cout.width(6); cout << right << "a" << endl; cout << "b" << endl; cout << "c" << endl;
会给你的
> a >b >c
输入和输出操纵器不粘,只在使用它们时出现一次.参数化操纵器各不相同,这里是每个操作器的简要说明:
setiosflags
让你手动设置标志,这里可以列出一个列表,所以它是粘性的.
resetiosflags
行为类似于setiosflags
除了它取消设置指定的标志.
setbase
设置插入流中的整数的基数(因此基数16中的17将是"11",而基数2中的17将是"10001").
setfill
设置填充字符以在使用时插入流中setw
.
setprecision
设置插入浮点值时要使用的小数精度.
setw
通过填充指定的字符,仅使下一个插入指定的宽度 setfill
以下评论的重要说明:
马丁:
@Chareles:然后通过这个要求,所有操纵器都是粘性的.除了在使用后似乎重置的setw.
查尔斯:
究竟!并且setw表现出不同行为的唯一原因是因为格式化输出操作需要显式地.width(0)输出流.
以下是导致上述结论的讨论:
查看代码,以下操纵器返回一个对象而不是一个流:
setiosflags resetiosflags setbase setfill setprecision setw
这是将操作仅应用于应用于流的下一个对象的常用技术.不幸的是,这并不妨碍它们变得粘稠.测试表明所有这些setw
都是粘性的.
setiosflags: Sticky resetiosflags:Sticky setbase: Sticky setfill: Sticky setprecision: Sticky
所有其他操纵器都返回一个流对象.因此,它们改变的任何状态信息必须记录在流对象中,因此是永久的(直到另一个操纵器改变状态).因此,以下操纵器必须是粘性操纵器.
[no]boolalpha [no]showbase [no]showpoint [no]showpos [no]skipws [no]unitbuf [no]uppercase dec/ hex/ oct fixed/ scientific internal/ left/ right
这些操纵器实际上对流本身而不是流对象执行操作(尽管从技术上讲,流是流对象状态的一部分).但我不相信它们会影响流对象状态的任何其他部分.
ws/ endl/ ends/ flush
结论是setw似乎是我的版本中唯一没有粘性的操纵器.
对于查尔斯来说,一个简单的技巧只能影响链中的下一个项目:
下面是一个示例如何使用对象临时更改状态,然后通过使用对象将其放回:
#include#include // 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 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
其原因width
并不显得"粘性"是某些保证操作调用.width(0)
上的输出流.那些是:
21.3.7.9 [lib.string.io]:
templatebasic_ostream & operator<<(basic_ostream & os, const basic_string & str);
22.2.2.2.2 [lib.facet.num.put.virtuals]:模板的所有do_put
重载num_put
.这些用于operator<<
采用a basic_ostream
和内置数字类型的重载.
22.2.6.2.2 [lib.locale.money.put.virtuals]:模板的所有do_put
重载money_put
.
27.6.2.5.4 [lib.ostream.inserters.character]:的重载operator<<
服用basic_ostream
和焦炭类型basic_ostream实例化的一个或char
签署char
或unsigned char
或指针这些字符类型的数组.
说实话,我不确定这个的基本原理,但是没有其他状态ostream
应该通过格式化的输出函数重置.当然,如果输出操作出现故障,可以设置badbit
和failbit
设置,但这应该是预期的.
我可以想到重置宽度的唯一原因是,如果在尝试输出一些分隔字段时,您的分隔符被填充,这可能会令人惊讶.
例如
std::cout << std::setw(6) << 4.5 << '|' << 3.6 << '\n'; " 4.5 | 3.6 \n"
要"纠正",这需要:
std::cout << std::setw(6) << 4.5 << std::setw(0) << '|' << std::setw(6) << 3.6 << std::setw(0) << '\n';
而使用重置宽度,可以生成所需的输出更短的:
std::cout << std::setw(6) << 4.5 << '|' << std::setw(6) << 3.6 << '\n';
setw()
仅影响下一次插入.这就是setw()
表现的方式.行为setw()
是一样的ios_base::width()
.我setw()
从cplusplus.com获取了我的信息.
您可以在此处找到完整的操纵器列表.从该链接开始,所有流标志应该设置为set,直到被另一个操纵器更改为止.一个说明有关left
,right
并internal
操纵:他们就像其他标志和你继续下去,直到改变.但是,它们仅在设置流的宽度时有效,并且必须在每一行设置宽度.所以,例如
cout.width(6); cout << right << "a" << endl; cout.width(6); cout << "b" << endl; cout.width(6); cout << "c" << endl;
会给你的
> a > b > c
但
cout.width(6); cout << right << "a" << endl; cout << "b" << endl; cout << "c" << endl;
会给你的
> a >b >c
输入和输出操纵器不粘,只在使用它们时出现一次.参数化操纵器各不相同,这里是每个操作器的简要说明:
setiosflags
让你手动设置标志,这里可以列出一个列表,所以它是粘性的.
resetiosflags
行为类似于setiosflags
除了它取消设置指定的标志.
setbase
设置插入流中的整数的基数(因此基数16中的17将是"11",而基数2中的17将是"10001").
setfill
设置填充字符以在使用时插入流中setw
.
setprecision
设置插入浮点值时要使用的小数精度.
setw
通过填充指定的字符,仅使下一个插入指定的宽度 setfill