如何在使用 boost 进行 QI 解析期间对数字进行舍入?
How to round a number during QI parsing with boost?
使用简单的 Boost qi 语法,我怎样才能让它四舍五入我的数字?
这是解析器:
factor =
float_ [_val = _1]
| ('-' >> factor [_val = -_1])
| ('+' >> factor [_val = _1])
;
这可以解析一个浮点数,也可以是负数。
我想舍入浮点数,所以我会在语法中添加这样的内容:
| ('~' >> factor [_val = round(_1)])
但这会导致编译时错误:
no type named ‘__type’ in ‘struct __gnu_cxx::__enable_if<false, double>’
这个错误对我来说不是太有用,你能帮忙吗?我希望能够舍入一个数字,即:
~1.8 -> 2
~1.2 -> 1
注意:我正在解析 phrase_parse
。
语义动作需要 Phoenix Actor,这是延迟函数。
选项:
- 适配宏https://www.boost.org/doc/libs/1_73_0/libs/phoenix/doc/html/phoenix/modules/function/adapting_functions.html
phoenix::function<>
phoenix::bind
- 自己写,详见https://www.boost.org/doc/libs/1_68_0/libs/spirit/doc/html/spirit/qi/tutorials/semantic_actions.html#spirit.qi.tutorials.semantic_actions.examples_of_semantic_actions
简化测试台
只是解析一个数字:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
int main() {
std::string s = "1.75";
double v;
if (qi::parse(begin(s), end(s), qi::double_, v)) {
std::cout << "Parsed: " << v << "\n";
}
}
打印 Live On Coliru:
Parsed: 1.75
适应
使用宏:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <cmath>
namespace qi = boost::spirit::qi;
int main() {
std::string s = "1.75";
double v;
if (qi::parse(begin(s), end(s), qi::double_, v)) {
std::cout << "Parsed: " << v << "\n";
std::cout << "Rounded: " << round(v) << "\n";
}
}
打印 Live On Coliru:
Parsed: 2
function<>
您可以在此处对签名进行硬编码:
boost::phoenix::function<double(*)(double)> round_(::round);
然而真正的力量来自于多态可调用对象:
struct round_f {
template <typename T> auto operator()(T const& v) const {
using std::round; // activate ADL
return round(v);
}
};
boost::phoenix::function<round_f> round_{};
现在您可以在任何具有兼容的自由函数重载 round
重载的类型上使用 round_
actor。如果明天您决定解析 long double
、float
或 boost::multiprecision::cpp_dec_float
.
,这会很方便
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <cmath>
namespace qi = boost::spirit::qi;
struct round_f {
template <typename T> auto operator()(T const& v) const {
using std::round; // activate ADL
return round(v);
}
};
boost::phoenix::function<round_f> round_{};
int main() {
std::string s = "1.75";
double v;
using namespace qi::labels;
if (qi::parse(begin(s), end(s), qi::double_ [ _val = round_(_1) ], v)) {
std::cout << "Parsed: " << v << "\n";
}
}
版画
Parsed: 2
使用phoenix::bind
作为较低级别的构建块,您可以绑定未包装的可调用对象:
if (qi::parse(begin(s), end(s), qi::double_
[ _val = phoenix::bind(round_f{}, _1) ], v))
{
std::cout << "Parsed: " << v << "\n";
}
如果不介意丑的话:
if (qi::parse(begin(s), end(s), qi::double_
[ _val = phoenix::bind(static_cast<double(&)(double)>(std::round), _1) ], v))
{
std::cout << "Parsed: " << v << "\n";
}
同时查看 Live On Coliru
使用简单的 Boost qi 语法,我怎样才能让它四舍五入我的数字?
这是解析器:
factor =
float_ [_val = _1]
| ('-' >> factor [_val = -_1])
| ('+' >> factor [_val = _1])
;
这可以解析一个浮点数,也可以是负数。
我想舍入浮点数,所以我会在语法中添加这样的内容:
| ('~' >> factor [_val = round(_1)])
但这会导致编译时错误:
no type named ‘__type’ in ‘struct __gnu_cxx::__enable_if<false, double>’
这个错误对我来说不是太有用,你能帮忙吗?我希望能够舍入一个数字,即:
~1.8 -> 2
~1.2 -> 1
注意:我正在解析 phrase_parse
。
语义动作需要 Phoenix Actor,这是延迟函数。
选项:
- 适配宏https://www.boost.org/doc/libs/1_73_0/libs/phoenix/doc/html/phoenix/modules/function/adapting_functions.html
phoenix::function<>
phoenix::bind
- 自己写,详见https://www.boost.org/doc/libs/1_68_0/libs/spirit/doc/html/spirit/qi/tutorials/semantic_actions.html#spirit.qi.tutorials.semantic_actions.examples_of_semantic_actions
简化测试台
只是解析一个数字:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
int main() {
std::string s = "1.75";
double v;
if (qi::parse(begin(s), end(s), qi::double_, v)) {
std::cout << "Parsed: " << v << "\n";
}
}
打印 Live On Coliru:
Parsed: 1.75
适应
使用宏:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <cmath>
namespace qi = boost::spirit::qi;
int main() {
std::string s = "1.75";
double v;
if (qi::parse(begin(s), end(s), qi::double_, v)) {
std::cout << "Parsed: " << v << "\n";
std::cout << "Rounded: " << round(v) << "\n";
}
}
打印 Live On Coliru:
Parsed: 2
function<>
您可以在此处对签名进行硬编码:
boost::phoenix::function<double(*)(double)> round_(::round);
然而真正的力量来自于多态可调用对象:
struct round_f {
template <typename T> auto operator()(T const& v) const {
using std::round; // activate ADL
return round(v);
}
};
boost::phoenix::function<round_f> round_{};
现在您可以在任何具有兼容的自由函数重载 round
重载的类型上使用 round_
actor。如果明天您决定解析 long double
、float
或 boost::multiprecision::cpp_dec_float
.
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <cmath>
namespace qi = boost::spirit::qi;
struct round_f {
template <typename T> auto operator()(T const& v) const {
using std::round; // activate ADL
return round(v);
}
};
boost::phoenix::function<round_f> round_{};
int main() {
std::string s = "1.75";
double v;
using namespace qi::labels;
if (qi::parse(begin(s), end(s), qi::double_ [ _val = round_(_1) ], v)) {
std::cout << "Parsed: " << v << "\n";
}
}
版画
Parsed: 2
使用phoenix::bind
作为较低级别的构建块,您可以绑定未包装的可调用对象:
if (qi::parse(begin(s), end(s), qi::double_
[ _val = phoenix::bind(round_f{}, _1) ], v))
{
std::cout << "Parsed: " << v << "\n";
}
如果不介意丑的话:
if (qi::parse(begin(s), end(s), qi::double_
[ _val = phoenix::bind(static_cast<double(&)(double)>(std::round), _1) ], v))
{
std::cout << "Parsed: " << v << "\n";
}
同时查看 Live On Coliru