M.M*_*M.M 6 c++ iostream facets c++11
Coliru的示例代码:
#include <iostream>
#include <sstream>
#include <string>
int main()
{
double d; std::string s;
std::istringstream iss("234cdefipxngh");
iss >> d;
iss.clear();
iss >> s;
std::cout << d << ", '" << s << "'\n";
}
Run Code Online (Sandbox Code Playgroud)
我在这里读N3337(可能与C++ 11相同).在[istream.formatted.arithmetic]中我们有(释义):
operator>>(double& val);
与插入器的情况一样,这些提取器依赖于语言环境的num_get <>(22.4.2.1)对象来执行解析输入流数据.这些提取器表现为格式化的输入函数(如27.7.2.2.1中所述).构造sentry对象后,转换就像执行以下代码片段一样:
typedef num_get< charT,istreambuf_iterator<charT,traits> > numget;
iostate err = iostate::goodbit;
use_facet< numget >(loc).get(*this, 0, *this, err, val);
setstate(err);
查看22.4.2.1:
此操作的详细信息分三个阶段进行
- 阶段1:确定转换说明符
- 阶段2:从中提取字符并确定第1 阶段中确定的转换规范所期望格式的相应char值.
- 阶段3:存储结果
在阶段2的描述中,对我来说,将整个事情粘贴在这里太长了.但是它清楚地表明在尝试转换之前应该提取所有字符; 而且应该提取以下字符:
0123456789abcdefxABCDEFX+-
decimal_point()
thousands_sep()
最后,第3阶段的规则包括:
- 对于浮点值,该函数
strtold
.要存储的数值可以是以下之一:
- 如果转换函数无法转换整个字段,则为零.
这似乎都清楚地指明了我的代码的输出应该是0, 'ipxngh'
.但是,它实际上输出了其他东西.
这是编译器/库的错误吗?是否有任何条款我忽略了一个区域设置来改变第二阶段的行为?(在另一个问题中,有人发布了一个实际提取字符的系统示例,但也提取了ipxn
不在N3337中指定的列表中的提取).
正如虚幻所指出的,第2阶段的文本是相关的:
如果丢弃是真的,那么如果'.' 尚未累积,然后记住角色的位置,但否则角色会被忽略.否则,如果'.' 已经累积,角色被丢弃,第2阶段终止.如果它没有被丢弃,则进行检查以确定是否
c
允许作为阶段1返回的转换说明符的输入字段的下一个字符.如果是,则累积它.如果该字符被丢弃或累积,则in进入++ in并且处理返回到阶段2的开头.
因此,如果字符在允许字符列表中,但不是有效字符,则阶段2可以终止%g
.它没有确切地说,但可能这是指fscanf
C99 的定义,它允许:
- 一个非空的十进制数字序列,可选地包含一个小数点字符,然后是6.4.4.2中定义的可选指数部分;
- 一个0x或0X,然后是一个非空的十六进制数字序列,可选地包含一个小数点字符,然后是6.4.4.2中定义的可选二进制指数部分;
- INF或INFINITY,忽略大小写
- NAN或NAN(n-char-sequence opt),忽略NAN部分的情况,其中:
并且
除了"C"语言环境之外,可以接受其他特定于语言环境的主题序列表单.
所以,实际上Coliru输出是正确的; 事实上,处理必须尝试验证提取的字符序列,直到有效输入为止%g
,同时提取每个字符.
下一个问题:这是允许的,因为在线程我挂早些时候,接受i
,n
,p
等在第2阶段?
这些是有效字符%g
,但它们不在允许第2阶段读取的原子列表中(即c == 0
对于我的最新引用,因此字符既不丢弃也不累积).
这是一团糟,因为gcc/libstdc ++和clang/libc ++的实现都不一致.目前还不清楚"检查是否允许c作为第1阶段返回的转换说明符的输入字段的下一个字符"是指,但我认为使用短语"next character"表示检查应该是上下文敏感(即,取决于已经累积的字符),因此例如,"21abc"
在'a'
遇到时应该停止解析.这与LWG问题2041中的讨论是一致的,该问题在C++ 11的起草过程中删除后将该句子添加回标准.libc ++没有这样做是错误17782.
另一方面,libstdc ++拒绝解析"0xABp-4"
过去0
,实际上它基于标准显然是不一致的(它应该解析"0xAB"
为hexfloat,正如C99 fscanf
规范明确允许的那样%g
).
的接受i
,p
以及n
不受标准允许的.见LWG第2381期.
该标准非常精确地描述了处理 - 它必须由指定的代码片段"仿佛"完成,它不接受这些字符.比较它们添加的LWG问题221的分辨率x
和X
字符列表,因为num_get
如下所述不会解析0x
整数输入.
Clang/libc ++接受"inf"和"nan"以及hexfloats但不接受"infinity"作为扩展.见错误19611.