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

时间:2018-05-10 17:00:50

标签: c++ boost boost-spirit boost-spirit-x3

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

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

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错误,关于&#34;未解析的外部符号引用&#34;:
 Pastebin.com link with the errors 关于他们的任何想法? 提前谢谢。

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

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

1 个答案:

答案 0 :(得分:2)

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

E.g。在test函数中,参数为std::string&,因此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;

可悲的是,你没有显示整个代码,所以你必须自己检查。

备注

  1. 重新使用标签类型是灾难的秘诀。我不认为可以工作。规则标签是在分离的编译单元的情况下调度实现函数的内容。解决它:

    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&amp;球员();    impl :: player_vector_type const&amp; player_vector();

    注意:w.r.t应该没问题。 static initialization order fiasco

  3. 在变体上使用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));
    };
    

    使用

    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. 由于船长
  6. (+x3::graph)仍匹配所有输入
  7. 相反,你想要一个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];
    
  8. 我建议更简洁地编写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;
        }
    }
    
  9. 完整演示

    查看 Live On Wandbox

    • 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"