C ++中的noskipws演示 [英] Demonstration of noskipws in C++

查看:104
本文介绍了C ++中的noskipws演示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用C ++的noskipws机械手,并编写了以下代码.

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
    string first, middle, last;

    istringstream("G B Shaw") >> first >> middle >> last;
    cout << "Default behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
    istringstream("G B Shaw") >> noskipws >> first >> middle >> last;
    cout << "noskipws behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
}

我希望得到以下输出:

预期产量

Default behavior: First Name = G, Middle Name = B, Last Name = Shaw
noskipws behavior: First Name = G, Middle Name = , Last Name = B

输出

Default behavior: First Name = G, Middle Name = B, Last Name = Shaw
noskipws behavior: First Name = G, Middle Name = , Last Name = Shaw

我修改了此代码,使其可用于此类字符,并且效果很好.

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
    char first, middle, last;

    istringstream("G B S") >> first >> middle >> last;
    cout << "Default behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
    istringstream("G B S") >> noskipws >> first >> middle >> last;
    cout << "noskipws behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
}

我知道cin是如何工作的,我无法弄清楚为什么在string情况下它会以这种方式工作.

解决方案

std::istringstream("G B S") >> std::noskipws >> first >> middle >> last;

对字符串进行提取时,首先清除字符串并将字符插入其缓冲区.

21.4.8.9插入器和提取器

 template<class charT, class traits, class Allocator>
 basic_istream<charT, traits>&
     operator>>(basic_istream<charT, traits>& is,
                basic_string<charT, traits, Allocator>& str);

效果:表现为格式化的输入函数(27.7.2.2.1).构造哨兵对象后,如果哨兵转换为true,则调用str.erase() ,然后从is中提取字符,并将其追加到str中,就像通过调用str.append(1, c). [. ..]

第一次读取会将字符串"G"提取到first中.对于第二次提取,由于设置了std::noskipws格式标志,因此无法清除任何前导空格,因此不会提取任何内容.因此,将清除字符串,然后由于未放入任何字符而导致提取失败.这是上面子句的延续:

21.4.8.9插入器和提取器(续)

[...]提取并附加字符,直到发生以下任何一种情况:

  • n个字符被存储;

  • 文件结尾出现在输入序列上;

  • isspace(c, is.getloc())对于下一个可用输入为true 字符c.

当流确定提取失败时,将std::ios_base::failbit设置为流状态,指示错误.

从这时开始,任何和所有的I/O尝试都将失败,除非清除了流状态.如果没有清除所有错误的流状态,提取器将无法运行,并且将无法运行.这意味着对last的提取不会执行任何操作,并且会保留上一次提取(没有std::noskipws的提取)所具有的值,因为流没有清除了字符串./p>


关于使用char起作用的原因:在C或C ++中,字符没有格式要求.任何字符都可以提取到char类型的对象中,这就是尽管设置了std::noskipws还是看到正确输出的原因:

27.7.2.2.3/1 [istream ::提取器]

template<class charT, class traits>
basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>& in,
                                         charT& c);

效果:行为类似于in的格式化输入成员(如27.7.2.2.1中所述).构造哨兵对象后,如果可用,则从in中提取一个字符,并将其存储在c中. .否则,该函数将调用in.setstate(failbit).

提取器的语义会将字符存储在其操作数(如果可用)中.它不限制空格(甚至不限制EOF字符!).它将像正常字符一样提取它.

I was trying out the noskipws manipulator in C++ and I wrote following code.

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
    string first, middle, last;

    istringstream("G B Shaw") >> first >> middle >> last;
    cout << "Default behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
    istringstream("G B Shaw") >> noskipws >> first >> middle >> last;
    cout << "noskipws behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
}

I expect the following output:

Expected Output

Default behavior: First Name = G, Middle Name = B, Last Name = Shaw
noskipws behavior: First Name = G, Middle Name = , Last Name = B

Output

Default behavior: First Name = G, Middle Name = B, Last Name = Shaw
noskipws behavior: First Name = G, Middle Name = , Last Name = Shaw

I modified this code to make it work for chars like this and it works perfectly fine.

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
    char first, middle, last;

    istringstream("G B S") >> first >> middle >> last;
    cout << "Default behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
    istringstream("G B S") >> noskipws >> first >> middle >> last;
    cout << "noskipws behavior: First Name = " << first << ", Middle Name = " << middle << ", Last Name = " << last << '\n';
}

I know how cin works and I wasn't able to figure out why it works this way in case of string.

解决方案

std::istringstream("G B S") >> std::noskipws >> first >> middle >> last;

When an extraction is performed on strings, the string is first cleared and characters are inserted into its buffer.

21.4.8.9 Inserters and extractors

 template<class charT, class traits, class Allocator>
 basic_istream<charT, traits>&
     operator>>(basic_istream<charT, traits>& is,
                basic_string<charT, traits, Allocator>& str);

Effects: Behaves as a formatted input function (27.7.2.2.1). After constructing a sentry object, if the sentry converts to true, calls str.erase() and then extracts characters from is and appends them to str as if by calling str.append(1, c). [...]

The first read will extract the string "G" into first. For the second extraction, nothing will be extracted because the std::noskipws format flag is set, disabling the clearing of leading whitespace. Because of this, the string is cleared and then the extraction fails because no characters were put in. Here is the continuation of the above clause:

21.4.8.9 Inserters and extractors (Cont.)

[...] Characters are extracted and appended until any of the following occurs:

  • n characters are stored;

  • end-of-file occurs on the input sequence;

  • isspace(c, is.getloc()) is true for the next available input character c.

When the stream determines a failed extraction the std::ios_base::failbit is set in the stream state indicating an error.

From this point on any and all attempts at I/O will fail unless the stream state is cleared. The extractor becomes inoperable and it will not run given a stream state not cleared of all its errors. This means that the extraction into last doesn't do anything and it retains the value it had at the previous extraction (the one without std::noskipws) because the stream did not clear the string.


As for the reason why using char works: Characters have no formatting requirements in C or C++. Any and all characters can be extracted into a object of type char, which is the reason why you're seeing the correct output despite std::noskipws being set:

27.7.2.2.3/1 [istream::extractors]

template<class charT, class traits>
basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>& in,
                                         charT& c);

Effects: Behaves like a formatted input member (as described in 27.7.2.2.1) of in. After a sentry object is constructed a character is extracted from in, if one is available, and stored in c. Otherwise, the function calls in.setstate(failbit).

The semantics for the extractor will store a character into its operand if one is available. It doesn't delimit upon whitespace (or even the EOF character!). It will extract it just like a normal character.

这篇关于C ++中的noskipws演示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆