我有一个struct Base
没有字段的摘要(只有抽象方法)和struct A
,两者都struct B
继承自Base
不同的字段。
是否有可能解析a A
或a B
并将规则存储在a中的规则shared_ptr<Base>
?
我想这样做是为了解析一些A
或B
将其存储在的容器中shared_ptr<Base>
。
这是结构的定义:
#include <iostream>
using namespace std;
struct Base
{
virtual void operator() const = 0;
};
struct A : Base
{
int value;
void operator() const override { cout << "Hello A: " << x << endl; };
};
struct B : Base
{
float value;
void operator() const override { cout << "Hello B: " << x << endl; };
};
struct BaseContainer
{
multimap<string, shared_ptr<Base>> container;
}
假设a BaseContainer
是由某些输入格式定义的,例如:
name: A value
name: B value
name: A value
where name
is a placeholder for a string used as a key for the multimap
in BaseContainer
, then A
or B
is a keyword for generating a struct A
or struct B
, and value is the value stored in the container.
How would I write a parser BaseContainer
?
The real example I want to apply it to is more complicated, struct A
and struct B
does not have same number of fields in it so please don't answer with something too specific to that example.
Thank you.
So there's two questions here, I feel:
有关此问题的方法2的小演示:
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>
#include <map>
#include <iomanip> // std::quoted
struct Base {}; // dynamic polymorphism not required for us now, no problem if you want it
struct A : Base {
int value;
void operator()() const { std::cout << "Hello A: " << value << std::endl; };
};
struct B : Base {
float value;
void operator()() const { std::cout << "Hello B: " << value << std::endl; };
};
using Node = boost::variant<A, B>;
struct BaseContainer {
using Map = std::multimap<std::string, Node>;
Map container;
};
BOOST_FUSION_ADAPT_STRUCT(A, value)
BOOST_FUSION_ADAPT_STRUCT(B, value)
BOOST_FUSION_ADAPT_STRUCT(BaseContainer, container)
namespace qi = boost::spirit::qi;
template <typename It>
struct Parser : qi::grammar<It, BaseContainer()> {
Parser() : Parser::base_type(start) {
using namespace qi;
_key = lexeme['"' >> *('\\' >> char_ | ~char_('"')) >> '"'];
_a_node = "A(" >> int_ >> ")";
_b_node = "B(" >> float_ >> ")";
_node = _a_node | _b_node;
_pair = '{' >> _key >> ',' >> _node >> '}';
_container = '{' >> -(_pair % ',') >> '}';
start = skip(space) [ _container ];
BOOST_SPIRIT_DEBUG_NODES((start)(_container)(_pair)(_key)(_node)(_a_node)(_b_node))
}
private:
qi::rule<It, BaseContainer()> start;
// lexeme
qi::rule<It, std::string()> _key;
using Skipper = qi::space_type;
using Pair = std::pair<std::string, Node>;
qi::rule<It, BaseContainer::Map(), Skipper> _container;
qi::rule<It, Pair(), Skipper> _pair;
qi::rule<It, Node(), Skipper> _node;
qi::rule<It, A(), Skipper> _a_node;
qi::rule<It, B(), Skipper> _b_node;
};
int main() {
Parser<std::string::const_iterator> const p;
for (std::string const input : {
R"({})",
R"({ { "one", A(42) } })",
R"({ { "two", B(3.14) } })",
R"({ { "three", A( -42 ) }, { "four", B( -3.14 ) } })",
})
{
std::cout << "-------\n";
std::cout << "Parsing " << input << "\n";
auto f = begin(input), l = end(input);
BaseContainer result;
if (qi::parse(f, l, p, result)) {
for (auto const& [k,v] : result.container) {
std::cout << " Key " << std::quoted(k) << ": ";
boost::apply_visitor([](auto const& node) { node(); }, v);
}
} else {
std::cout << "Parse failed\n";
}
if (f!=l) {
std::cout << "Remaining unparsed: " << std::quoted(std::string(f,l)) << "\n";
}
}
}
版画
-------
Parsing {}
-------
Parsing { { "one", A(42) } }
Key "one": Hello A: 42
-------
Parsing { { "two", B(3.14) } }
Key "two": Hello B: 3.14
-------
Parsing { { "three", A( -42 ) }, { "four", B( -3.14 ) } }
Key "four": Hello B: -3.14
Key "three": Hello A: -42
在我的问题中,基类没有任何属性,我将其用作接口(如Java的接口
Interface
),问题与第一点的链接有点不同。那为什么不可能呢?没有人说这不可能吗?如果将它用作接口,那么按照定义,您正在谈论多态方面。我认为我的第二个链接详细说明了这一点。纯粹的静态继承方面很简单,没有基础数据成员(只是不要说有一个基类,完成了)。
是的,第二个答案最后可能更合适。但是我还没有弄清楚如何使它与一起使用
boost::variant
。修改BaseContainer
以存储variant<A, B>
?你想改变你的问题吗?如果您选择了其他AST选项,也许可以发布一个新的
非常感谢,希望您花时间吃午饭!我很抱歉耽搁了。因此,使用
variant
和访客模式对我来说是最好的解决方案,再次感谢。