C++实现解析器组合子的Seq函数如何推导Tuple返回类型
问题分析
最初的编译错误核心原因是:模板参数包T...之后的模板参数R无法被编译器自动推导,C++语法不支持参数包后的模板参数从函数实参推导,因此无法确定返回的std::function的签名类型。
现有实现的评价
你修改后的基于尾部返回类型+decltype推导的实现是符合语法要求的正确实现,可以在支持C++17及以上标准的编译器下正常编译运行。如果你的设计约束要求Seq必须返回std::function类型,该实现已经是当前约束下的最优写法,没有进一步简化的空间。
可优化方向
如果没有强制返回std::function的要求,还可以从以下角度优化:
- 消除不必要的类型擦除开销
std::function存在类型擦除的运行时开销,解析器组合子通常直接返回lambda对象本身,不需要额外包装,C++14及以上标准可以直接用auto推导返回类型,代码更简洁,调用性能更高:
template <typename ...T> auto Seq(T... a) { return [=](Stream* stream) { return std::tuple{ a(stream)... }; }; }
- 补充失败短路逻辑
当前实现会无条件执行所有传入的解析器,即便前面的解析器已经匹配失败,也会继续执行后续逻辑,不符合序列解析器的常规行为。可以增加流位置回滚和短路逻辑:只要任意一个解析器失败,直接回滚流到解析前的位置,整个序列返回失败状态。 - 修复调用代码的悬空引用问题
原调用代码中auto& charA = Char('a');将临时std::function对象绑定到非const左值引用,属于未定义行为,会触发悬空引用崩溃,去掉引用符即可:
auto charA = Char('a'); auto seq = Seq(Char('#'), charA);
内容的提问来源于stack exchange,提问作者StackThePile
相关产品推荐
相关产品推荐

