使用boost::spirit::qi(error_invalid_expression)解析glm::vec3的3个浮
parsing 3 floats for glm::vec3 using boost::spirit::qi (error_invalid_expression)
我可以解析一个浮点并打印它。(test1
,test2
)不知怎的,我无法构建一个解析三个浮点值的规则。我的最终目标是解析三个浮动并将它们保存到glm::vec3
中。
- 我的规则似乎不正确:
qi::lexeme[qi::float_ << ' ' << qi::float_ << ' ' << qi::float_]
- 我不确定我是否正确使用
BOOST_FUSION_ADAPT_STRUCT
这里有一个来源来展示我到目前为止的想法:
#include <iostream>
#include <string>
#include <glmglm.hpp>
#include <boostspiritincludeqi.hpp>
#include <boostfusionincludeadapt_struct.hpp>
namespace qi = boost::spirit::qi;
void test1()
{
std::string test = "1.2";
auto it = test.begin();
if (qi::phrase_parse(it, test.end(), qi::float_, qi::space) && (it == test.end()))
std::cout << "test 1 ok" << std::endl;
else
std::cout << "test 1 not ok" << std::endl;
}
void test2()
{
std::string test = "1.2";
auto it = test.begin();
float f;
if (qi::phrase_parse(it, test.end(), qi::float_, qi::space, f) && (it == test.end()))
std::cout << "test 2 ok " << f << std::endl;
else
std::cout << "test 2 not ok" << std::endl;
}
void test3()
{
std::string test = "1.2 2.2 3.3";
qi::rule<std::string::iterator, qi::space_type> VEC3;
//error_invalid_expression
VEC3 = qi::lexeme[qi::float_ << ' ' << qi::float_ << ' ' << qi::float_];
auto it = test.begin();
if (qi::phrase_parse(it, test.end(), VEC3, qi::space) && (it == test.end()))
std::cout << "test 3 ok " << std::endl;
else
std::cout << "test 3 not ok" << std::endl;
}
BOOST_FUSION_ADAPT_STRUCT(
glm::vec3,
(float, x)
(float, y)
(float, z)
)
void test4()
{
std::string test = "1.2 2.2 3.3";
qi::rule<std::string::iterator, qi::space_type> VEC3;
//error_invalid_expression
VEC3 = qi::lexeme[qi::float_ << ' ' << qi::float_ << ' ' << qi::float_];
glm::vec3 result;
auto it = test.begin();
if (qi::phrase_parse(it, test.end(), VEC3, qi::space, result) && (it == test.end()))
{
std::cout << "test 4 ok (" << result.x << ", " << result.y << ", " << result.z << ")"<< std::endl;
}
else
std::cout << "test 4 not ok" << std::endl;
}
int main(int argc, char ** argv)
{
test1();
test2();
test3();
test4();
}
test4
函数包含了我尝试完成的所有操作。
编辑:
正如建议的那样,有两件事需要改变:
void test4()
{
std::string test = "1.2 2.2 3.3";
qi::rule<std::string::iterator, glm::vec3(), qi::space_type> VEC3;
//error_invalid_expression
VEC3 = qi::lexeme[qi::float_ >> ' ' >> qi::float_ >> ' ' >> qi::float_];
glm::vec3 result;
auto it = test.begin();
if (qi::phrase_parse(it, test.end(), VEC3, qi::space, result) && (it == test.end()))
{
std::cout << "test 4 ok (" << result.x << ", " << result.y << ", " << result.z << ")"<< std::endl;
}
else
std::cout << "test 4 not ok" << std::endl;
}
我同意Pete Becker的观点<越简单越好>越简单越好>
现在,既然你最终要使用spirit,让我们看看什么可以更简单:
-
使用c++11改编:
BOOST_FUSION_ADAPT_STRUCT(glm::vec3, x, y, z)
-
你可以不使用adapt(演示中的
simpler
) -
如果您正在执行顶级
lexeme[]
指令,则可以(应该)从规则声明中删除队长。参见stackoverflow.com/questions/17072987/boost spirit captain issues/17073965#10773965 -
更好的是,这里没有可读性规则。事实上,你会有一个更大的语法和多个规则确保不要在每次解析时实例化语法(为了提高效率)
演示测试台Coliru直播
//#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <glm/glm.hpp>
#include <iostream>
#include <string>
namespace qi = boost::spirit::qi;
glm::vec3 simpler(std::string const& test) {
auto it = test.begin();
glm::vec3 result;
using namespace qi;
if (parse(it, test.end(),
float_ >> ' ' >> float_ >> ' ' >> float_ >> eoi,
result.x, result.y, result.z))
{
return result;
}
throw std::runtime_error("invalid input");
}
glm::vec3 use_skipper(std::string const& test) {
auto it = test.begin();
glm::vec3 result;
using namespace qi;
if (phrase_parse(it, test.end(),
float_ >> float_ >> float_ >> eoi,
space, result.x, result.y, result.z))
{
return result;
}
throw std::runtime_error("invalid input");
}
BOOST_FUSION_ADAPT_STRUCT(glm::vec3, x, y, z)
glm::vec3 with_adapt(std::string const& test) {
auto it = test.begin();
glm::vec3 result;
using namespace qi;
if (phrase_parse(it, test.end(), float_ >> float_ >> float_ >>eoi, space, result))
{
return result;
}
throw std::runtime_error("invalid input");
}
int main() {
struct { glm::vec3 (&f)(std::string const&); std::string name; } tests[] = {
{simpler, "simpler"},
{use_skipper, "use_skipper"},
{with_adapt, "with_adapt"}
};
for (auto t : tests) try {
glm::vec3 v = t.f("1.2 2.2 3.3");
std::cout << t.name << " ok (" << v.x << ", " << v.y << ", " << v.z << ")n";
} catch(std::exception const& e) {
std::cout << t.name << " fail (" << e.what() << ")n";
}
}
使用x3,您可以稍微轻一点。这并不是说工作量减少了,但编译器的工作量肯定减轻了。
与跳过前/后的r.t.相比有细微的差异,但如果有一个包含语法的队长
序列解析器操作符是>>
,在您的规则中使用它而不是<<
VEC3 = qi::lexeme[qi::float_ >> ' ' >> qi::float_ >> ' ' >> qi::float_];
您已经在规则中指定了一个空格队长,因此可以通过删除lexeme
指令并让队长自动跳过空格来进一步简化它(除非您希望确保输入之间只有一个空格字符)。
VEC3 = qi::float_ >> qi::float_ >> qi::float_;
此外,如果您希望规则返回值,则需要将该签名添加到规则类型中
qi::rule<std::string::iterator, glm::vec3(), qi::space_type> VEC3;
这与您看到的编译错误无关,但在#include
指令中使用正斜杠,该指令适用于所有平台。
#include <boost/spirit/include/qi.hpp>
对于一些简单的东西来说,似乎需要做大量的工作。
#include <iostream>
#include <string>
#include <sstream>
int main() {
std::string test = "1.2 2.2 3.3";
float f1, f2, f3;
std::istringstream in(test);
in >> f1 >> f2 >> f3;
return 0;
}
- 继承函数的重载解析
- 基类中的函数名称解析
- 提升精神:解析布尔表达式并简化为规范范式
- 我正在使用嵌套的while循环来解析具有多行的文本文件,但由于某种原因,它只通过第一行,我不知道为什么
- 了解 GLM- openGL 中的相机转换
- gcc和c++17的过载解析失败
- OpenGl glm rotate
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- 构造函数和转换运算符之间的重载解析
- 未解析的外部符号_MsiLocateComponentW@12.
- '尝试解析可变参数模板时无法推断出'T的模板参数
- OpenGL 和 GLM 矩阵无法正确扩展,总是按比例缩小
- 非类型指针和引用模板参数,以及在编译时如何/为什么解析它们.c++
- 发布旋转矩阵(openGL/glm)
- C++的解析器在可以区分比较和模板实例化之前会做什么?
- 如何在 cpp 中解析此文件?
- 如何在 glRotatef 中使用 glm::mat4
- 在C++中使用 gRPC 时未解析的外部符号
- IDE (CLion) 无法解析C++模板类型
- 使用boost::spirit::qi(error_invalid_expression)解析glm::vec3的3个浮