scnlib,现代C++中用于替换scanf和istream的库

现代C++标准库已经有了fmt,用于替换printf和ostream。相应的scnlib用于替换scanf和istream。语法和fmt类似。

// Scanning an int, using scnlib
int i;
scn::scan("123", "{}", i):
// i == 123

//scanning using sscanf
int i;
std::sscanf("123", "%d", &i);

可以看到语法简单了许多,不用记忆特定的格式规格如”%d”等。

scnlib的缺陷

相比scanf而言,scnlib中的格式规格不能丢弃一些部分。比如某一字符串有两个数,而我们只对第二个感兴趣,这时用sscanf很容易做到。

#include <iostream>
#include <cstdio>
int main(){
  int a;
  std::sscanf( "1 8", "%*d %d" , &a);
  std::cout<<a<<std::endl; //output 8
}

而scnlib使用discard函数来丢弃某字段,

int i{};
// 123 is discarded, 456 is read into `i`
auto result = scn::scan("123 456", "{} {}", scn::discard<T>(), i);
// result == true
// i == 456

这对于转发是个巨大的缺陷。

比如相比sscanf实现的myscan

 auto myscan= [](const char* buf,const char* fmt_str, auto&... args)
 {
   std::sscanf( buf, fmt , &args...);
 }

myscan可方便的实现转发, myscan(“1 5 8”, “%d %*d %d”, a, b), 而对于scnlib的scn::scan是不可能的。要实现正确丢弃,scn::discard需要插入合适的位置。比如为实现像myscan(“1 5 8”, “%d %*d %d”, a, b)一样能丢弃中间位置的字段,函数实现里scn::discard<…>()需要插入args…展开式中间,这在C++里完全不可能。

Posted 2023-02-26