X3:非终端解析器上的链接器错误(未解析的外部符号“parse_rule”)

2024-04-26

首先我使用的是MSVC 2017(最新版本)。 这是我的非终结符解析器的代码:

播放器.hpp

namespace parse
{
    namespace impl
    {
        namespace x3 = boost::spirit::x3;

        struct _tag;

        using player_type = x3::rule<_tag, PlayerIterator>;
        using player_vector_type = x3::rule<_tag, std::vector<PlayerIterator>>;
        BOOST_SPIRIT_DECLARE(player_type);
        BOOST_SPIRIT_DECLARE(player_vector_type);
    }; //impl

    impl::player_type player();
    impl::player_vector_type player_vector();
}; //parse

播放器.cpp

namespace parse
{
    namespace impl
    {
        const player_type player = "player";
        const player_vector_type player_vector = "player_vector";
        auto player_find = [](auto &ctx)
        {
            auto &attr = x3::_attr(ctx);
            if(attr.which() == 0)
                return x3::_val(ctx) = PlayerManager::find(boost::get<int>(attr));
            return x3::_val(ctx) = PlayerManager::find(boost::get<std::string>(attr));
        };
        auto player_vector_find = [](auto &ctx)
        {
            return x3::_val(ctx) = PlayerManager::vector_find(x3::_attr(ctx));
        };
        auto const player_def = (x3::int_ | (+x3::char_))[player_find];
        auto const player_vector_def = (((+x3::char_)[player_vector_find]));
        BOOST_SPIRIT_DEFINE(player);
        BOOST_SPIRIT_DEFINE(player_vector);
        BOOST_SPIRIT_INSTANTIATE(player_type, iterator_type, context_type);
        BOOST_SPIRIT_INSTANTIATE(player_vector_type, iterator_type, context_type);
    } //impl
    parse::impl::player_type player() { return impl::player; }
    parse::impl::player_vector_type player_vector() { return impl::player_vector; }
}//parse

我收到有关“未解析的外部符号引用”的链接器 LNK2019 错误:
Pastebin.com 链接有错误 https://pastebin.com/HcYnaFyi关于他们有什么想法吗? 提前致谢。

编辑: 这就是我在源文件中的调用方式:

void test(std::string &params)
{
    std::tuple<PlayerIterator, std::vector<PlayerIterator>, std::string> tuple;
    if (!x3::phrase_parse(params.begin(), params.end(), parse::player()>> parse::player_vector() >> (+x3::char_), x3::space,tuple))
    {
        std::cout << "Error: Parsing failed" << std::endl;
        return;
    }
    std::cout << "Parsing succeded" << std::endl;
    std::cout << "Found player, size of player vector: "<< std::get<1>(tuple).size() << ", also parsed string:" << std::get<2>(tuple);
    return;
};

我愿意打赌 10 美元,因为您在实例化时与上下文或迭代器类型不匹配。

例如。在你的test函数,参数是std::string&, hence params.begin()std::string::iterator。如果你有iterator_type配置如下:

using iterator_type = std::string::const_iterator; // very sensible!

因为迭代器类型与实际需要的类型不匹配,所以您将有未解析的外部。

对于上下文来说也是如此。为了匹配您的调用,它需要完全相同:

using context_type = x3::phrase_parse_context<x3::space_type>::type;

遗憾的是您没有显示完整的代码,因此您必须自己检查。

Notes

  1. 重复使用标签类型会导致灾难。我不认为can工作。规则标签是在分离编译单元的情况下调度实现函数的内容。修理它:

    using player_type        = x3::rule<struct player_tag,        PlayerIterator>;
    using player_vector_type = x3::rule<struct player_vector_tag, std::vector<PlayerIterator>>;
    
  2. 复制规则似乎很浪费,考虑通过引用返回:

    impl::player_type const&player(); impl::player_vector_type const&player_vector();

    注意:这应该没问题。静态初始化顺序惨败 https://isocpp.org/wiki/faq/ctors

  3. using which()变体上是反模式。您可以更换

    auto player_find = [](auto &ctx) {
        auto &attr = x3::_attr(ctx);
        if (attr.which() == 0)
            return x3::_val(ctx) = PlayerManager::find(boost::get<int>(attr));
        return x3::_val(ctx) = PlayerManager::find(boost::get<std::string>(attr));
    };
    

    With

    auto find = [](auto const& key) { return PlayerManager::find(key); };
    auto player_find = [](auto &ctx) {
        return x3::_val(ctx) = boost::apply_visitor(find, x3::_attr(ctx));
    };
    
  4. (+x3::char_)始终匹配所有输入

  5. (+x3::graph)由于船长的原因,仍然匹配所有输入
  6. 相反,你想要一个词位:

    auto const name              = x3::lexeme[+x3::graph];
    auto const player_def        = (x3::int_ | name) [player_find];
    auto const player_vector_def = name[ player_vector_find];
    
  7. 我可以建议写一下test功能更加简洁:

    void test(std::string const &params) {
        auto comment_ = x3::lexeme[+x3::char_];
    
        PlayerIterator player;
        PlayerIterators vec;
        std::string comment;
        auto tuple = std::tie(player, vec, comment);
    
        if (phrase_parse(params.cbegin(), params.cend(), parse::player() >> parse::player_vector() >> comment_, x3::space, tuple)) {
            std::cout << "Parsing succeded" << std::endl;
            std::cout << "Found player, size of player vector: " << vec.size() << "\n";
            std::cout << "Also parsed string: " << std::quoted(comment);
        } else {
            std::cout << "Error: Parsing failed" << std::endl;
        }
    }
    

完整演示

See it Live On Wandbox https://wandbox.org/permlink/8gcrM81P2NDSbJts

  • stuff.h

    包含模型PlayerManager

    #pragma once
    #include <string>
    #include <vector>
    #include <iostream>
    
    struct PlayerIterator { };
    using PlayerIterators = std::vector<PlayerIterator>;
    
    struct PlayerManager {
        static PlayerIterator              find(std::string const&)        { std::cout << __PRETTY_FUNCTION__ << "\n"; return {}; } 
        static PlayerIterator              find(int)                       { std::cout << __PRETTY_FUNCTION__ << "\n"; return {}; } 
        static PlayerIterators vector_find(std::string const&) { std::cout << __PRETTY_FUNCTION__ << "\n"; return {}; } 
    };
    
  • test.h

    #pragma once
    #include <boost/spirit/home/x3.hpp>
    #include <boost/fusion/adapted.hpp>
    #include "stuff.h"
    
    namespace x3 = boost::spirit::x3;
    
    namespace parse
    {
        namespace impl
        {
            using player_type        = x3::rule<struct player_tag,        PlayerIterator>;
            using player_vector_type = x3::rule<struct player_vector_tag, PlayerIterators>;
    
            BOOST_SPIRIT_DECLARE(player_type)
            BOOST_SPIRIT_DECLARE(player_vector_type)
        } //impl
    
        impl::player_type const& player();
        impl::player_vector_type const& player_vector();
    } //parse
    
  • test.cpp

    #include "stuff.h"
    #include "test.h"
    
    using iterator_type = std::string::const_iterator;
    using context_type = x3::phrase_parse_context<x3::space_type>::type;
    
    namespace parse {
        namespace impl {
            const player_type player               = "player";
            const player_vector_type player_vector = "player_vector";
    
            auto find               = [](auto const& key) { return PlayerManager::find(key); } ;
            auto player_find        = [](auto &ctx)       { return x3::_val(ctx) = boost::apply_visitor(find, x3::_attr(ctx)); } ;
            auto player_vector_find = [](auto &ctx)       { return x3::_val(ctx) = PlayerManager::vector_find(x3::_attr(ctx)); } ;
    
            auto const name              = x3::lexeme[+x3::graph];
            auto const player_def        = (x3::int_ | name) [player_find];
            auto const player_vector_def = name[ player_vector_find];
    
            BOOST_SPIRIT_DEFINE(player)
            BOOST_SPIRIT_DEFINE(player_vector)
    
            BOOST_SPIRIT_INSTANTIATE(player_type,        iterator_type, context_type)
            BOOST_SPIRIT_INSTANTIATE(player_vector_type, iterator_type, context_type)
        } // namespace impl
    
        parse::impl::player_type const& player()               { return impl::player; }
        parse::impl::player_vector_type const& player_vector() { return impl::player_vector; }
    } // namespace parse
    
  • main.cpp

    #include "stuff.h"
    #include "test.h"
    #include <iostream>
    #include <iomanip>
    
    void test(std::string const &params) {
        auto comment_ = x3::lexeme[+x3::char_];
    
        PlayerIterator player;
        PlayerIterators vec;
        std::string comment;
        auto tuple = std::tie(player, vec, comment);
    
        if (phrase_parse(params.cbegin(), params.cend(), parse::player() >> parse::player_vector() >> comment_, x3::space, tuple)) {
            std::cout << "Parsing succeded" << std::endl;
            std::cout << "Found player, size of player vector: " << vec.size() << "\n";
            std::cout << "Also parsed string: " << std::quoted(comment);
        } else {
            std::cout << "Error: Parsing failed" << std::endl;
        }
    }
    
    int main() {
        test("42 someword # bogus trailing comment");
    }
    

Prints:

static PlayerIterator PlayerManager::find(int)
static PlayerIterators PlayerManager::vector_find(const std::string &)
Parsing succeded
Found player, size of player vector: 0
Also parsed string: "# bogus trailing comment"
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

X3:非终端解析器上的链接器错误(未解析的外部符号“parse_rule”) 的相关文章

随机推荐

  • 如何将函数应用于嵌套列表?

    我需要获取嵌套列表中变量的最大值 对于某个站号 s 和某个成员 m mylist s m 其形式为 station date time member bias 6019 2011 08 06 12 00 mbr003 86 6019 201
  • URLError:

    只是想让这段代码直接运行它的基本代码Python 金融 import datetime import matplotlib pyplot as plt from matplotlib finance import quotes histor
  • 复制/粘贴到 Word 时如何保留 rstudio 的格式?

    我想在 Word 2010 中重现我的代码 脚本是用 rstudio 编写的 我想在粘贴到 Word 时保留 rstudio 的格式 主要是 我喜欢 rstudio 使用的字体颜色和间距 我发现当我从 SAS 粘贴到 Word 时 格式会被
  • 如何为pandas数据框中的不同组分配唯一的ID?

    如何根据特定条件为 pandas 数据框中创建的组分配唯一 ID 例如 我有一个名为 df 的数据框 其结构如下 名称标识用户 日期时间标识用户访问资源的日期 时间 Name Datetime Bob 26 04 2018 12 00 00
  • 未找到 Firebase 框架

    我一直在尝试将我的项目迁移到 cocoapods 我觉得我快到了 但我陷入了困境 ld 找不到架构 x86 64 的 Firebase 框架 错误 链接器命令失败 退出代码为 1 使用 v 查看调用 我正在尝试使用我的 app xcwork
  • SwiftUI 预览的 Xcode Canvas 不显示

    我正在尝试从 Xcode 11 运行新的 Canvas 功能 但 Canvas 不会显示 我究竟做错了什么 这个新的 Xcode 功能应该在不运行应用程序的情况下显示我的 SwiftUI 视图的实时预览 当您使用 SwiftUI 创建自定义
  • 图像调整大小性能:System.Drawing 与 System.Windows.Media

    我遇到了需要调整大量图像大小的情况 这些图像目前在文件系统上存储为 jpg 文件 但我希望稍后在项目中内存中只有 byte 源图像大小是可变的 但输出应该是 3 个不同的预定大小 应保留长宽比 用空白填充原始图像 即 将调整非常高的图像大小
  • 未知处理时间的进度条

    我正在开发启动 停止 重新启动 Windows 服务的 winform c 我想放置一个进度条 直到操作完成 我是 net 编程新手 请帮助我实现这一目标 当您不知道需要多长时间时 您就无法展示有意义的进展 您无法知道 服务启动需要 1 到
  • 使用 Postman 获取并存储 cookie 的值 [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我需要获取 cookie 的值 该值仅在我在邮递员中发送请求时创建 我已经尝试了一切 但我不知道如何实现这一目标 我还需要存储该值以便在我的
  • 根据具体数据计算锯齿波和三角波

    我需要计算三角形和锯齿波 但由于我的模型和我能够使用的数据 它有点复杂 但也许我只是感到困惑 我能够计算我的正弦波 但我并没有真正使用帧计数器 我所做的是 计算theta increment下次需要计算样本时可以使用的变量 这工作起来是这样
  • 根据时间变量对两个表中的一对 COUNT 求和

    花了一个多小时的时间寻找这个问题的答案 但运气不佳 我有两个具有相同列名的区域表 我可以根据以下查询为任一表提供结果列表 将 Table2 替换为 Table1 SELECT Table1 YEAR FORMAT COUNT Table1
  • GitHub Actions 工作流程不响应其他工作流程中的推送事件

    我创建了一个工作流程 在推送分支 A 时自动将分支 A 合并到分支 B 中 并创建了一个在推送分支 B 时运行的工作流程 但是 当推送分支 B 时 工作流不会运行 这是 GitHub 规范吗 如果是这样 我想知道是否有文档或问题明确说明了这
  • 基于 GPO DisplayName 而不是 Id 备份 GPO

    因此 我正在备份域控制器的所有 GPO 我注意到 Backup GPO cmdlet 备份 GPOS 的方式非常不友好 默认情况下 它为每个以 ID 命名的 GPO 创建一个文件夹 该文件夹甚至与其 GPOID GUID 不匹配 这是一个示
  • AWS Elastic Beanstalk 无效的二进制包

    我正在致力于将项目从 Heroku 迁移到 AWS 部署后我不断收到错误消息 无效的 ELF 标头 我在使用 AWS Lambda 时发现了类似问题的帖子 但我不明白为什么 Elastic Beanstalk 中的二进制包会出现问题 Ela
  • 我需要异常排序 mysql 结果

    我正在尝试从当前日期开始对结果进行升序排序 这就是我现在使用的 SELECT FROM friends JOIN bdays ON bdays user friends friendname WHERE username userid OR
  • PyZMQ 是否处理为每个新客户端连接创建线程?

    我正在使用 PyZMQ 创建请求 回复服务器 并且我试图弄清楚为每个新客户端连接创建线程的行为是否由 PyZMQ 自动处理 最终 我试图弄清楚来自一个客户端的请求需要很长时间才能回复 是否会阻止来自所有其他客户端的请求 通常 我会在 Pyt
  • 使用SQL Server Management Studio远程连接docker容器

    Context 我正在尝试构建一个开发 SQL Server 我可以在其上继续学习 SQL 并使用 Microsoft SQL Server Management Studio SSMS 在 Windows PC 上访问 因此 我将 Adv
  • 将 Logcat 保存到 Android 设备中的文本文件

    我在 Android 设备中运行应用程序时发现一些崩溃 但模拟器中没有显示 所以我需要将 Logcat 保存在设备内存或 SD 卡中的文本文件中 您能建议我这样做的好方法吗 在应用程序的开头使用 Application 类 这允许正确的文件
  • Jquery:检查div是否包含文本,然后执行操作

    我试图在 jQuery 中检查 div 是否包含一些文本 然后添加一个类 如果包含 所以我写了这样的东西 if field gt div field item text indexOf someText 0 somediv addClass
  • X3:非终端解析器上的链接器错误(未解析的外部符号“parse_rule”)

    首先我使用的是MSVC 2017 最新版本 这是我的非终结符解析器的代码 播放器 hpp namespace parse namespace impl namespace x3 boost spirit x3 struct tag usin