振奋精神 assign_to_* 自定义点数
boost spirit assign_to_* customization points
我正在尝试了解提升精神 assign_to_*
自定义点数的工作原理。
这是我正在使用的一个例子:
我在语法规则中有这个解析器:
int_ >> lit(':') >> char_
我希望将结果放入此结构中:
struct IntAndChar{
int i;
char c;
};
(这只是使用自定义点的示例,因此我不会使用 BOOST_FUSION_ADAPT_STRUCT
或语义操作。)
我以为我可以定义 assign_to_attribute_from_value
的特化,但我只通过这种方式获得了 int,第二个元素被删除了。
有人可以给我提示以了解其工作原理吗?
您不想分配给属性¹。相反,您希望 将 boost::fusion::vector2<int, char>
转换为 IntAndChar
.
因此,让我们开始告诉 spirit 我们的类型不是容器类的:
template<>
struct is_container<IntAndChar, void> : mpl::false_ { };
接下来,告诉它如何在属性的原始形式和熟化形式之间转换 e:
template<>
struct transform_attribute<IntAndChar, fusion::vector2<int, char>, qi::domain, void> {
using Transformed = fusion::vector2<int, char>;
using Exposed = IntAndChar;
using type = Transformed;
static Transformed pre(Exposed&) { return Transformed(); }
static void post(Exposed& val, Transformed const& attr) {
val.i = fusion::at_c<0>(attr);
val.c = fusion::at_c<1>(attr);
}
static void fail(Exposed&) {}
};
就是这样!不过有一个问题。除非您触发转换,否则它不会起作用。 The docs say:
It is invoked by Qi rule, semantic action and attr_cast, [...]
1。使用 qi::rule
(不是很有帮助)
所以这是一个使用 rule
的解决方案:
int main() {
using It = std::string::const_iterator;
qi::rule<It, boost::fusion::vector2<int, char>(), qi::space_type> rule = qi::int_ >> ':' >> qi::char_;
//qi::rule<It, IntAndChar(), qi::space_type> rule = qi::attr_cast(qi::int_ >> ':' >> qi::char_);
for (std::string const input : { "123:a", "-4 : \r\nq" }) {
It f = input.begin(), l = input.end();
IntAndChar data;
bool ok = qi::phrase_parse(f, l, rule, qi::space, data);
if (ok) std::cout << "Parse success: " << data.i << ", " << data.c << "\n";
else std::cout << "Parse failure ('" << input << "')\n";
if (f != l) std::cout << "Remaining unparsed input: '" << std::string(f, l) << "'\n";
}
}
打印:
Parse success: 123, a
Parse success: -4, q
当然,这种方法需要你拼写boost::fusion::vector2<int, char>
,这很繁琐且容易出错。
2。使用 qi::attr_cast
您可以使用qi::attr_cast
触发转换:
qi::rule<It, IntAndChar(), qi::space_type> rule = qi::attr_cast<IntAndChar, boost::fusion::vector2<int, char> >(qi::int_ >> ':' >> qi::char_);
// using deduction:
qi::rule<It, IntAndChar(), qi::space_type> rule = qi::attr_cast<IntAndChar>(qi::int_ >> ':' >> qi::char_);
// using even more deduction:
qi::rule<It, IntAndChar(), qi::space_type> rule = qi::attr_cast(qi::int_ >> ':' >> qi::char_);
CAVEAT That should work. However, due to very subtle behaviour (bugs?) you need to deep-copy the Proto expression tree there, in order for it to work without Undefined Behaviour:
qi::rule<It, IntAndChar(), qi::space_type> rule = qi::attr_cast(qi::copy(qi::int_ >> ':' >> qi::char_));
综合起来,我们甚至可以不用 qi::rule
:
int main() {
using It = std::string::const_iterator;
for (std::string const input : { "123:a", "-4 : \r\nq" }) {
It f = input.begin(), l = input.end();
IntAndChar data;
bool ok = qi::phrase_parse(f, l, qi::attr_cast(qi::copy(qi::int_ >> ':' >> qi::char_)), qi::space, data);
if (ok) std::cout << "Parse success: " << data.i << ", " << data.c << "\n";
else std::cout << "Parse failure ('" << input << "')\n";
if (f != l) std::cout << "Remaining unparsed input: '" << std::string(f, l) << "'\n";
}
}
版画
Parse success: 123, a
Parse success: -4, q
¹(除非您想将 IntAndChar
视为容器,这是另一回事)
我正在尝试了解提升精神 assign_to_*
自定义点数的工作原理。
这是我正在使用的一个例子:
我在语法规则中有这个解析器:
int_ >> lit(':') >> char_
我希望将结果放入此结构中:
struct IntAndChar{
int i;
char c;
};
(这只是使用自定义点的示例,因此我不会使用 BOOST_FUSION_ADAPT_STRUCT
或语义操作。)
我以为我可以定义 assign_to_attribute_from_value
的特化,但我只通过这种方式获得了 int,第二个元素被删除了。
有人可以给我提示以了解其工作原理吗?
您不想分配给属性¹。相反,您希望 将 boost::fusion::vector2<int, char>
转换为 IntAndChar
.
因此,让我们开始告诉 spirit 我们的类型不是容器类的:
template<>
struct is_container<IntAndChar, void> : mpl::false_ { };
接下来,告诉它如何在属性的原始形式和熟化形式之间转换 e:
template<>
struct transform_attribute<IntAndChar, fusion::vector2<int, char>, qi::domain, void> {
using Transformed = fusion::vector2<int, char>;
using Exposed = IntAndChar;
using type = Transformed;
static Transformed pre(Exposed&) { return Transformed(); }
static void post(Exposed& val, Transformed const& attr) {
val.i = fusion::at_c<0>(attr);
val.c = fusion::at_c<1>(attr);
}
static void fail(Exposed&) {}
};
就是这样!不过有一个问题。除非您触发转换,否则它不会起作用。 The docs say:
It is invoked by Qi rule, semantic action and attr_cast, [...]
1。使用 qi::rule
(不是很有帮助)
所以这是一个使用 rule
的解决方案:
int main() {
using It = std::string::const_iterator;
qi::rule<It, boost::fusion::vector2<int, char>(), qi::space_type> rule = qi::int_ >> ':' >> qi::char_;
//qi::rule<It, IntAndChar(), qi::space_type> rule = qi::attr_cast(qi::int_ >> ':' >> qi::char_);
for (std::string const input : { "123:a", "-4 : \r\nq" }) {
It f = input.begin(), l = input.end();
IntAndChar data;
bool ok = qi::phrase_parse(f, l, rule, qi::space, data);
if (ok) std::cout << "Parse success: " << data.i << ", " << data.c << "\n";
else std::cout << "Parse failure ('" << input << "')\n";
if (f != l) std::cout << "Remaining unparsed input: '" << std::string(f, l) << "'\n";
}
}
打印:
Parse success: 123, a
Parse success: -4, q
当然,这种方法需要你拼写boost::fusion::vector2<int, char>
,这很繁琐且容易出错。
2。使用 qi::attr_cast
您可以使用qi::attr_cast
触发转换:
qi::rule<It, IntAndChar(), qi::space_type> rule = qi::attr_cast<IntAndChar, boost::fusion::vector2<int, char> >(qi::int_ >> ':' >> qi::char_);
// using deduction:
qi::rule<It, IntAndChar(), qi::space_type> rule = qi::attr_cast<IntAndChar>(qi::int_ >> ':' >> qi::char_);
// using even more deduction:
qi::rule<It, IntAndChar(), qi::space_type> rule = qi::attr_cast(qi::int_ >> ':' >> qi::char_);
CAVEAT That should work. However, due to very subtle behaviour (bugs?) you need to deep-copy the Proto expression tree there, in order for it to work without Undefined Behaviour:
qi::rule<It, IntAndChar(), qi::space_type> rule = qi::attr_cast(qi::copy(qi::int_ >> ':' >> qi::char_));
综合起来,我们甚至可以不用 qi::rule
:
int main() {
using It = std::string::const_iterator;
for (std::string const input : { "123:a", "-4 : \r\nq" }) {
It f = input.begin(), l = input.end();
IntAndChar data;
bool ok = qi::phrase_parse(f, l, qi::attr_cast(qi::copy(qi::int_ >> ':' >> qi::char_)), qi::space, data);
if (ok) std::cout << "Parse success: " << data.i << ", " << data.c << "\n";
else std::cout << "Parse failure ('" << input << "')\n";
if (f != l) std::cout << "Remaining unparsed input: '" << std::string(f, l) << "'\n";
}
}
版画
Parse success: 123, a
Parse success: -4, q
¹(除非您想将 IntAndChar
视为容器,这是另一回事)