看来你的情况是反序列化。
解析和实例化将比类工厂的一个虚函数调度慢得多。这是一个草图,正在解析:
Point(3, 4.5);
Circle(Point(0,0), 42e3);
Rectangle(Point(7, -0.87654), Point (77, 9e2));
进入以下层次结构:
struct Shape {
virtual ~Shape() = default;
virtual void print(std::ostream&) const {};
friend std::ostream& operator<<(std::ostream& os, Shape const& s) {
s.print(os);
return os;
}
};
struct Point : Shape {
double x, y;
virtual void print(std::ostream& os) const override {
os << "Point(" << x << "," << y << ")";
}
};
struct Circle : Shape {
Point origin;
double radius;
virtual void print(std::ostream& os) const override {
os << "Circle(" << origin << "," << radius << ")";
}
};
struct Rectangle : Shape {
Point topleft, bottomright;
virtual void print(std::ostream& os) const override {
os << "Rectangle(" << topleft << "," << bottomright << ")";
}
};
解析器正在使用 Spirit X3:
namespace Parser {
using namespace boost::spirit::x3;
template <typename T>
auto as = [](auto expr) { return rule<struct _, T>{"rule"} = expr; };
auto point = as<Point>(eps >> "Point" >> "(" >> double_ >> ',' >> double_ >> ')');
auto circle = as<Circle>(eps >> "Circle" >> "(" >> point >> ',' >> double_ >> ')');
auto rectangle = as<Rectangle>(eps >> "Rectangle" >> "(" >> point >> ',' >> point >> ')');
auto shape = point | circle | rectangle;
auto push = [](auto& ctx) {
auto vis = [&](auto& shape) { _val(ctx).insert(std::move(shape)); };
apply_visitor(vis, _attr(ctx));
};
auto shapes = rule<struct _, Shapes>{} //
= skip(space)[shape[push] % ';'];
} // namespace Parser
让我们使用PolyCollection 来存储多态类型。如果您愿意,显然可以使用指针容器,但您提到性能是一个问题。
int main() {
std::string const& input = R"(Point(3, 4.5);
Circle(Point(0,0), 42e3);
Rectangle(Point(7, -0.87654), Point (77, 9e2)))";
Shapes parsed;
if (parse(begin(input), end(input), Parser::shapes, parsed)) {
for (auto& s : parsed) {
std::cout << "Instantiated: " << s << "\n";
}
}
}
打印
Instantiated: Rectangle(Point(7,-0.87654),Point(77,900))
Instantiated: Circle(Point(0,0),42000)
Instantiated: Point(3,4.5)
现场演示
Live On Coliru
#include <iostream>
#include <typeinfo>
struct Shape {
virtual ~Shape() = default;
virtual void print(std::ostream&) const {};
friend std::ostream& operator<<(std::ostream& os, Shape const& s) {
s.print(os);
return os;
}
};
struct Point : Shape {
double x, y;
virtual void print(std::ostream& os) const override {
os << "Point(" << x << "," << y << ")";
}
};
struct Circle : Shape {
Point origin;
double radius;
virtual void print(std::ostream& os) const override {
os << "Circle(" << origin << "," << radius << ")";
}
};
struct Rectangle : Shape {
Point topleft, bottomright;
virtual void print(std::ostream& os) const override {
os << "Rectangle(" << topleft << "," << bottomright << ")";
}
};
#include <boost/poly_collection/base_collection.hpp>
using Shapes = boost::poly_collection::base_collection<Shape>;
#include <boost/fusion/adapted.hpp>
BOOST_FUSION_ADAPT_STRUCT(Point, x, y)
BOOST_FUSION_ADAPT_STRUCT(Circle, origin, radius)
BOOST_FUSION_ADAPT_STRUCT(Rectangle, topleft, bottomright)
#include <boost/spirit/home/x3.hpp>
namespace Parser {
using namespace boost::spirit::x3;
template <typename T>
auto as = [](auto expr) { return rule<struct _, T>{"rule"} = expr; };
auto point = as<Point>(eps >> "Point" >> "(" >> double_ >> ',' >> double_ >> ')');
auto circle = as<Circle>(eps >> "Circle" >> "(" >> point >> ',' >> double_ >> ')');
auto rectangle = as<Rectangle>(eps >> "Rectangle" >> "(" >> point >> ',' >> point >> ')');
auto shape = point | circle | rectangle;
auto push = [](auto& ctx) {
auto vis = [&](auto& shape) { _val(ctx).insert(std::move(shape)); };
apply_visitor(vis, _attr(ctx));
};
auto shapes = rule<struct _, Shapes>{} //
= skip(space)[shape[push] % ';'];
} // namespace Parser
int main() {
std::string const& input = R"(Point(3, 4.5);
Circle(Point(0,0), 42e3);
Rectangle(Point(7, -0.87654), Point (77, 9e2)))";
Shapes parsed;
if (parse(begin(input), end(input), Parser::shapes, parsed)) {
for (auto& s : parsed) {
std::cout << "Instantiated: " << s << "\n";
}
}
}