X3:非终端解析器上的链接器错误(未解析的外部符号"parse_rule") [英] X3: Linker Error (unresolved external symbol "parse_rule") on nonterminal parser

查看:62
本文介绍了X3:非终端解析器上的链接器错误(未解析的外部符号"parse_rule")的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我正在使用MSVC 2017(最新版本).这是我的非终端解析器代码:

First of all I am using MSVC 2017 (latest version). Here is my code for the nonterminal parser:

player.hpp

player.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

player.cpp

player.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链接有错误关于他们有什么想法吗?预先感谢.

I get linker LNK2019 errors about "unresolved external symbols referenced":
Pastebin.com link with the errors Any ideas about them? Thanks in advance.

这就是我在源文件中称呼它的方式:

That's how I call it in my source file:

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美元,说您在实例化中的上下文或迭代器类型不匹配.

I'm willing to bet $10 that you mismatched the context or iterator types on the instantiations.

例如在您的 test 函数中,参数为 std :: string& ,因此 params.begin()将为 std :: string:: iterator .如果您的 iterator_type 配置如下:

E.g. in your test function, the argument is std::string&, hence params.begin() will be std::string::iterator. If you had the iterator_type configured as follows:

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

您将拥有未解决的外部条件,因为迭代器类型与实际需要的类型不匹配.

you would have unresolved externals because the iterator type doesn't match the one actually required.

与上下文相同.要匹配您的调用,它必须完全是:

Same thing for the context. To match your invocation it needs to be exactly:

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

不幸的是,您没有显示完整的代码,因此您必须自己检查.

Sadly you didn't show the whole code, so you'll have to check on your own.

  1. 重用标签类型是灾难的秘诀.我认为不能起作用.在单独的编译单元的情况下,规则标签是用来调度实现功能的.修复它:

  1. re-using the tag type is recipe for disaster. I don't think it can work. The rule tags are what dispatches the implementation function in the case of separated compilation units. Fix it:

using player_type        = x3::rule<struct player_tag,        PlayerIterator>;
using player_vector_type = x3::rule<struct player_vector_tag, std::vector<PlayerIterator>>;

  • 复制规则似乎很浪费,请考虑按引用返回:

  • copying the rules seems wasteful, consider returning by reference:

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

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

    注意:这应该没事.静态初始化顺序惨败

    在变体上使用 which()是一种反模式.您可以替换

    using which() on a variant is an anti-pattern. You can replace

    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 find = [](auto const& key) { return PlayerManager::find(key); };
    auto player_find = [](auto &ctx) {
        return x3::_val(ctx) = boost::apply_visitor(find, x3::_attr(ctx));
    };
    

  • (+ x3 :: char _)始终匹配所有输入

    相反,您想要一个词素:

    Instead you wanted a lexeme:

    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];
    

  • 我可以建议更简洁地编写 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;
        }
    }
    

  • 完整演示

    查看 在魔盒上直播

    • 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");
    }
    

  • 打印:

    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"
    

    这篇关于X3:非终端解析器上的链接器错误(未解析的外部符号"parse_rule")的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆