Pot*_*ter 8 c++ unicode iostream facet
我正在写一个lambda演算解释器,用于娱乐和练习.我通过添加一个ctype将标点符号定义为空格的构面来获得iostream正确地标记化标识符:
struct token_ctype : ctype<char> {
mask t[ table_size ];
token_ctype()
: ctype<char>( t ) {
for ( size_t tx = 0; tx < table_size; ++ tx ) {
t[tx] = isalnum( tx )? alnum : space;
}
}
};
Run Code Online (Sandbox Code Playgroud)
(classic_table()可能更干净但是在OS X上不起作用!)
然后在我点击标识符时交换方面:
locale token_loc( in.getloc(), new token_ctype );
…
locale const &oldloc = in.imbue( token_loc );
in.unget() >> token;
in.imbue( oldloc );
Run Code Online (Sandbox Code Playgroud)
网上似乎有一些令人惊讶的lambda演算代码.到目前为止,我发现的大部分内容都充满了unicode ?字符.所以我想尝试添加Unicode支持.
但ctype<wchar_t>完全不同于ctype<char>.没有主表; 有两种方法do_isx2 do_scan_is,和do_scan_not.所以我这样做了:
struct token_ctype : ctype< wchar_t > {
typedef ctype<wchar_t> base;
bool do_is( mask m, char_type c ) const {
return base::do_is(m,c)
|| (m&space) && ( base::do_is(punct,c) || c == L'?' );
}
const char_type* do_is
(const char_type* lo, const char_type* hi, mask* vec) const {
base::do_is(lo,hi,vec);
for ( mask *vp = vec; lo != hi; ++ vp, ++ lo ) {
if ( *vp & punct || *lo == L'?' ) *vp |= space;
}
return hi;
}
const char_type *do_scan_is
(mask m, const char_type* lo, const char_type* hi) const {
if ( m & space ) m |= punct;
hi = do_scan_is(m,lo,hi);
if ( m & space ) hi = find( lo, hi, L'?' );
return hi;
}
const char_type *do_scan_not
(mask m, const char_type* lo, const char_type* hi) const {
if ( m & space ) {
m |= punct;
while ( * ( lo = base::do_scan_not(m,lo,hi) ) == L'?' && lo != hi )
++ lo;
return lo;
}
return base::do_scan_not(m,lo,hi);
}
};
Run Code Online (Sandbox Code Playgroud)
(对于平面格式的道歉;预览以不同方式转换了标签.)
代码不那么优雅.我更好地表达了这样一种观念,即只有标点符号才是额外的空格,但如果我有原始数据,那么这就好了classic_table.
有更简单的方法吗?我真的需要所有那些重载吗?(测试显示do_scan_not在这里是无关紧要的,但我更广泛地思考.)我是否首先滥用方面?以上是否正确?实施更少的逻辑会更好吗?
(已经一年了没有实质性的答案,同时我也了解了很多关于iostreams的知识\xe2\x80\xa6)
\n\n自定义方面专门用于服务字符串提取运算符in >> token。该运算符是根据use_facet< ctype< wchar_t > >( in.getloc() ).is( ios::space, c )“下一个可用输入字符c ”来定义的。(\xc2\xa721.3.7.9)ctype::is只是 的存根ctype::do_is,因此看起来就do_is足够了。
尽管如此,最新版本的 GCC 标准库确实operator>>以scan_is. 问题是,do_scan_is然后将其实现为一系列对do_is、虚拟调度等的调用。头文件描述do_scan_is为用户优化的钩子。
因此,似乎假设规则庇护了仅提供第一个覆盖的实现。
\n\n请注意,检索掩码值的第二个覆盖是一个奇怪的情况。它可以按照第一种方式来实现,通过一点一点地低效地构建掩码。在 GCC 中,它是通过系统调用来实现的,每个字符需要 15 次调用,逐位构建掩码,效率低下。这似乎牺牲了性能和兼容性。幸运的是,似乎没有人使用它。
\n\n不管怎样,这一切都很好,但是简单地使用编写一个标记生成器streambuf_iterator<wchar_t>更容易,更具可扩展性,并且简化了异常处理。