使用名称标记std :: function?

gct*_*gct 5 c++ parsing c++11 std-function

我正在研究一个解析器组合库,我真的很喜欢我的解析器只是一个可调用的对象:

typedef std::function<parse_result(parse_stream)> parser;
Run Code Online (Sandbox Code Playgroud)

这使得解析器组合器很好,例如:

parser operator &(parser a, parser b) { return both(a,b); }
Run Code Online (Sandbox Code Playgroud)

我想要两个功能:

1)我希望自动将字符串文字提升为解析器,以便您可以执行以下操作:

parser option = "<" & regexp("[^+>]+");
Run Code Online (Sandbox Code Playgroud)

2)我希望解析器有一个名称,我可以用它来进行错误格式化.在上面的"both"解析器的情况下,我可以打印我预期的a.name()和b.name().

到目前为止我尝试过的两个选项是

  1. 一个可调用的解析器类,这让我可以从字符串和std :: function实例构建,但是一般的callable必须首先转换为std :: function并从那里转换为解析器,而C++不会进行两次隐式转换

  2. 继承自std :: function所以我可以隐式转换函数,但这似乎有很多陷阱只是将callables转换为解析器.

有没有人对如何构建这个有任何想法?

Yak*_*ont 3

你不需要 std 函数的原始 typedef ;你的解析器不仅仅是一个标准函数。

struct parser: std::function<parse_result(parse_stream)>{
  using base = std::function<parse_result(parse_stream)>;
  using base::base;
};
Run Code Online (Sandbox Code Playgroud)

这应该允许

parser p = []( parse_stream str ) { return parse_result(7); };
Run Code Online (Sandbox Code Playgroud)

因为我们使用继承构造函数来std::function公开parser.

虽然您可以覆盖:

parser operator&(parser a, parser b) { return both(a,b); }
Run Code Online (Sandbox Code Playgroud)

通过放入or&的命名空间来使用 typedef 版本,我建议不要这样做;标准中已经有讨论限制这种模板参数 ADL。对于裸类型,放置此类运算符重载的位置是明确的。parse_resultparse_streamparser

此外,某些类型不能在类外部重载,例如&=. 有了 astruct你就可以在那里做。

这些都没有修复

parser option = "<" & regexp("[^+>]+");
Run Code Online (Sandbox Code Playgroud)

因为这里的问题是右侧不知道左侧在做什么(除非regexp是返回解析器的函数)。

首先这样做:

struct parser: std::function<parse_result(parse_stream)>{
  using base = std::function<parse_result(parse_stream)>;
  parser( char const* str ):
    base( [str=std::string(str)](parse_stream stream)->parse_result { /* do work */ } )
  {}
  parser( char c ):
    base( [c](parse_stream str)->parse_result { /* do work */ } )
  {}
  using base::base;
};
Run Code Online (Sandbox Code Playgroud)

然后你可以添加

namespace parsing {
  // parser definition goes here
  inline namespace literals {
    inline parser operator""_p( char const* str ) { return str; }
  }
}
Run Code Online (Sandbox Code Playgroud)

meansusing namespace parsing::literals"hello"_p一个尝试解析字符串的解析器"hello"