当前位置:  开发笔记 > 编程语言 > 正文

哪个iomanip操纵器"粘"?

如何解决《哪个iomanip操纵器"粘"?》经验,为你挑选了3个好方法。

我最近遇到了一个问题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]:

template
  basic_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签署charunsigned char或指针这些字符类型的数组.

说实话,我不确定这个的基本原理,但是没有其他状态ostream应该通过格式化的输出函数重置.当然,如果输出操作出现故障,可以设置badbitfailbit设置,但这应该是预期的.

我可以想到重置宽度的唯一原因是,如果在尝试输出一些分隔字段时,您的分隔符被填充,这可能会令人惊讶.

例如

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,rightinternal操纵:他们就像其他标志和继续下去,直到改变.但是,它们仅在设置流的宽度时有效,并且必须在每一行设置宽度.所以,例如

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



1> Martin York..:

以下评论的重要说明:

马丁:

@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)`输出流.
返回流__Must__的对象是粘性的,而返回对象的对象可能是粘性的,但不是必需的.我将用约翰的信息更新答案.

2> CB Bailey..:

其原因width并不显得"粘性"是某些保证操作调用.width(0)上的输出流.那些是:

21.3.7.9 [lib.string.io]:

template
  basic_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签署charunsigned char或指针这些字符类型的数组.

说实话,我不确定这个的基本原理,但是没有其他状态ostream应该通过格式化的输出函数重置.当然,如果输出操作出现故障,可以设置badbitfailbit设置,但这应该是预期的.

我可以想到重置宽度的唯一原因是,如果在尝试输出一些分隔字段时,您的分隔符被填充,这可能会令人惊讶.

例如

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';



3> David Brown..:

setw()仅影响下一次插入.这就是setw()表现的方式.行为setw()是一样的ios_base::width().我setw()从cplusplus.com获取了我的信息.

您可以在此处找到完整的操纵器列表.从该链接开始,所有流标志应该设置为set,直到被另一个操纵器更改为止.一个说明有关left,rightinternal操纵:他们就像其他标志和继续下去,直到改变.但是,它们仅在设置流的宽度时有效,并且必须在每一行设置宽度.所以,例如

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


"哪个iomanip操纵器'粘'?"
推荐阅读
ar_wen2402851455
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有