使用Boost.Spirit解析RFC3339 Duration遇编译错误求助
问题背景
使用Boost.Spirit解析RFC3339定义的Duration(已移除周支持),定义了包含年、月、日、时、分、秒的Duration结构体并通过BOOST_FUSION_ADAPT_STRUCT适配,但编译时出现如下错误:
/usr/include/boost/spirit/home/qi/detail/assign_to.hpp:153:20: error: no matching function for call to 'Duration::Duration(const int&)'
153 | attr = static_cast(val);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
错误根源是m_start规则的属性无法匹配Duration结构体对应的六整数序列,因不确定规则实际属性类型而使用了auto和copy指令,需要调整语法或采用其他解决方法。
解决方法
1. 显式指定规则属性类型
不要依赖auto推导规则属性,直接将规则的属性类型指定为Duration或对应的融合序列类型,让Spirit明确知道要绑定的目标类型:
#include <boost/spirit/include/qi.hpp> #include <boost/fusion/include/adapt_struct.hpp> struct Duration { int years = 0; int months = 0; int days = 0; int hours = 0; int minutes = 0; int seconds = 0; }; BOOST_FUSION_ADAPT_STRUCT(Duration, years, months, days, hours, minutes, seconds) namespace qi = boost::spirit::qi; template <typename Iterator> struct DurationGrammar : qi::grammar<Iterator, Duration()> { DurationGrammar() : DurationGrammar::base_type(m_start) { // 后续规则定义 } qi::rule<Iterator, Duration()> m_start; };
2. 对齐语法规则与结构体成员顺序
确保语法规则生成的属性序列顺序,和BOOST_FUSION_ADAPT_STRUCT中声明的结构体成员顺序完全一致。对于RFC3339中可选的时间分量,需要用qi::attr(0)为缺失的分量填充默认值,保证属性序列始终是6个int值:
m_start = qi::lit("P") >> (qi::int_ >> 'Y' | qi::attr(0)) >> (qi::int_ >> 'M' | qi::attr(0)) >> (qi::int_ >> 'D' | qi::attr(0)) >> -(qi::lit("T") >> (qi::int_ >> 'H' | qi::attr(0)) >> (qi::int_ >> 'M' | qi::attr(0)) >> (qi::int_ >> 'S' | qi::attr(0)) );
这里通过| qi::attr(0)处理可选分量,确保每个位置都能输出int值,匹配结构体的融合属性序列。
3. 直接绑定结构体成员赋值(可选)
如果需要更灵活地控制赋值逻辑,可以使用Boost.Phoenix直接绑定结构体成员,避免属性序列不匹配的问题:
#include <boost/spirit/include/phoenix.hpp> namespace phx = boost::phoenix; // 在语法构造函数中 m_start = qi::lit("P") >> -(qi::int_ >> 'Y')[phx::bind(&Duration::years, qi::_val) = qi::_1] >> -(qi::int_ >> 'M')[phx::bind(&Duration::months, qi::_val) = qi::_1] >> -(qi::int_ >> 'D')[phx::bind(&Duration::days, qi::_val) = qi::_1] >> -(qi::lit("T") >> -(qi::int_ >> 'H')[phx::bind(&Duration::hours, qi::_val) = qi::_1] >> -(qi::int_ >> 'M')[phx::bind(&Duration::minutes, qi::_val) = qi::_1] >> -(qi::int_ >> 'S')[phx::bind(&Duration::seconds, qi::_val) = qi::_1] );
这种方式不需要严格的属性序列匹配,直接为每个存在的分量赋值,缺失的分量保持结构体的默认值(需确保结构体成员有默认初始化)。
4. 保证结构体有默认构造能力
Spirit解析时需要先默认构造Duration对象再逐步赋值,因此结构体必须支持默认构造:
- 如果没有显式定义任何构造函数,编译器会自动生成默认构造函数;
- 如果有显式构造函数,需要手动添加默认构造函数(如
Duration() = default;)。
内容的提问来源于stack exchange,提问作者Aaron Wright

