Boost Karma:boost::optional未设置时生成默认文本的编译错误问题
解决Boost Spirit Karma编译错误:no member named 'is_compatible'
这个问题我之前也踩过坑,本质是你修改start_规则时,把属性类型不兼容的生成器用|组合到一起了,导致Spirit的属性兼容性检查模板找不到对应的处理逻辑,才抛出了这个编译错误。
错误原因分析
你原来的规则应该是针对boost::optional类型的(比如处理fo这个可选值),当你直接把它和输出'-'的字面量生成器组合时,两者的属性类型不匹配:
- 原规则的属性是
boost::optional<T>(需要一个可选值作为输入) lit('-')或者直接'-'生成器要么不需要属性,要么属性是char
Spirit Karma在组合生成器时,要求所有分支的属性必须能兼容(或者通过适配器调整),否则就会触发compute_compatible_component相关的编译错误,因为它找不到这两种属性之间的兼容逻辑。
可行的解决方案
最直接的方法是用karma::eps做条件分支,先检查optional是否有值,再分别处理两种情况:
#include <boost/spirit/include/karma.hpp> #include <boost/optional.hpp> #include <string> #include <iostream> namespace karma = boost::spirit::karma; int main() { boost::optional<std::string> fo; // fo = "foo"; // 取消注释则输出foo,注释则输出- // 定义规则,属性为boost::optional<std::string> karma::rule<std::back_insert_iterator<std::string>, boost::optional<std::string>()> start_; // 用eps做条件判断:如果optional有值,输出原内容;否则输出'-' start_ = karma::eps([](auto& ctx) { return _attr(ctx).is_initialized(); }) << karma::string // 提取optional中的string输出 | karma::lit('-'); // 无值时输出'-' std::string output; karma::generate(std::back_inserter(output), start_, fo); std::cout << output << std::endl; return 0; }
这里的关键点是:
karma::eps带一个lambda,用来检查当前属性(也就是你的optional变量)是否已初始化- 第一个分支只有在
optional有值时才会执行,karma::string会自动提取optional内部的字符串值 - 第二个分支
karma::lit('-')不需要属性输入,和规则的整体属性(optional<std::string>)兼容,因为它不消耗属性
这样修改后,规则的所有分支属性逻辑一致,就不会触发兼容性检查的编译错误了。
内容的提问来源于stack exchange,提问作者Addy
相关产品推荐
相关产品推荐

