X3:非终端解析器上的链接器错误(未解析的外部符号 "parse_rule")
X3: Linker Error (unresolved external symbol "parse_rule") on nonterminal parser
首先,我使用的是 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
我收到有关 "unresolved external symbols referenced":
的链接器 LNK2019 错误
Pastebin.com link with the errors
关于他们的任何想法?
提前致谢。
编辑:
这就是我在源文件中的调用方式:
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 美元,你不匹配实例化的上下文或迭代器类型。
例如在您的 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;
遗憾的是你没有展示完整的代码,所以你必须自己检查。
注释
重复使用标签类型会导致灾难。我不认为它 可以 工作。规则标签是在分离的编译单元的情况下调度实现函数的东西。修复它:
using player_type = x3::rule<struct player_tag, PlayerIterator>;
using player_vector_type = x3::rule<struct player_vector_tag, std::vector<PlayerIterator>>;
复制规则似乎很浪费,考虑引用返回:
impl::player_type const& player();
impl::player_vector_type常量&player_vector();
注意:这应该没问题w.r.t。 static initialization order fiasco
在变体上使用 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));
};
(+x3::char_)
总是匹配所有输入
(+x3::graph)
仍然匹配所有输入,因为船长
相反,你想要一个词素:
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"
首先,我使用的是 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
我收到有关 "unresolved external symbols referenced":
的链接器 LNK2019 错误
Pastebin.com link with the errors
关于他们的任何想法?
提前致谢。
编辑:
这就是我在源文件中的调用方式:
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 美元,你不匹配实例化的上下文或迭代器类型。
例如在您的 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;
遗憾的是你没有展示完整的代码,所以你必须自己检查。
注释
重复使用标签类型会导致灾难。我不认为它 可以 工作。规则标签是在分离的编译单元的情况下调度实现函数的东西。修复它:
using player_type = x3::rule<struct player_tag, PlayerIterator>; using player_vector_type = x3::rule<struct player_vector_tag, std::vector<PlayerIterator>>;
复制规则似乎很浪费,考虑引用返回:
impl::player_type const& player(); impl::player_vector_type常量&player_vector();
注意:这应该没问题w.r.t。 static initialization order fiasco
在变体上使用
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)); };
(+x3::char_)
总是匹配所有输入(+x3::graph)
仍然匹配所有输入,因为船长相反,你想要一个词素:
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"