重写ctype <wchar_t>

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在这里是无关紧要的,但我更广泛地思考.)我是否首先滥用方面?以上是否正确?实施更少的逻辑会更好吗?

Pot*_*ter 3

(已经一年了没有实质性的答案,同时我也了解了很多关于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足够了。

\n\n

尽管如此,最新版本的 GCC 标准库确实operator>>scan_is. 问题是,do_scan_is然后将其实现为一系列对do_is、虚拟调度等的调用。头文件描述do_scan_is为用户优化的钩子。

\n\n

因此,似乎假设规则庇护了仅提供第一个覆盖的实现。

\n\n

请注意,检索掩码值的第二个覆盖是一个奇怪的情况。它可以按照第一种方式来实现,通过一点一点地低效地构建掩码。在 GCC 中,它是通过系统调用来实现的,每个字符需要 15 次调用,逐位构建掩码,效率低下。这似乎牺牲了性能和兼容性。幸运的是,似乎没有人使用它。

\n\n
\n\n

不管怎样,这一切都很好,但是简单地使用编写一个标记生成器streambuf_iterator<wchar_t>更容易,更具可扩展性,并且简化了异常处理。

\n