X3:非终端解析器上的链接器错误(未解析的外部符号"parse_rule") [英] X3: Linker Error (unresolved external symbol "parse_rule") on nonterminal parser
问题描述
首先,我正在使用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 ¶ms)
{
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.
-
重用标签类型是灾难的秘诀.我认为不能起作用.在单独的编译单元的情况下,规则标签是用来调度实现功能的.修复它:
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 ¶ms) {
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 ¶ms) {
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屋!