[英]Segfault trying to use boost::spirit::qi parser in a class
[英]Iteratively populate a BGL graph by use of a boost spirit qi parser
這個問題是“具有提升精神的抽象語法樹的迭代更新”的后續。
已知:
要求是:
思路:
有沒有人有一些想法如何解決這個問題,還是指向某個方向?
謝謝
簡而言之:這很難實現。
如果想要將一些數據解析為BGL圖,最簡單的方法可能是使用BGL圖形適配器vector_as_graph。 給定此適配器並且鑒於boost精神解析器可以解析為向量,那么它是可能的。
enum { r, s, t, u, v, w, x, y, N };
char name[] = "rstuvwxy";
typedef std::vector < std::list < int > > Graph;
Graph g(N);
g[r].push_back(v);
g[s].push_back(r);
g[s].push_back(r);
g[s].push_back(w);
g[t].push_back(x);
g[u].push_back(t);
g[w].push_back(t);
g[w].push_back(x);
g[x].push_back(y);
g[y].push_back(u);
boost::print_graph(g, name);
我使用的解決方案是在boost精神域中解析給定的語法,然后執行到AST的轉換,以便表示為BGL圖。
最后的想法:應該注意的是,提升精神和BGL領域的學習曲線相當陡峭。 基於此,如果分開,可讀性和實現更容易。 不是說它無法解決。
回應你的
最后的想法:應該注意的是,提升精神和BGL領域的學習曲線相當陡峭。 基於此,如果分開,可讀性和實現更容易。 不是說它無法解決。
在你的回答中,我同意。 保持簡單的關鍵是分開關注點。 ( 僅僅因為鳳凰城讓你幾乎可以將任何東西綁在你的解析器中,並不意味着它是個好主意[1] 。 )
也許這個示例應用程序可以作為靈感?
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
#include <sstream>
using namespace boost;
typedef adjacency_list<setS, vecS, directedS> Graph;
std::vector<std::string> generate_file_data();
void merge_into(std::istream&& is, Graph& into);
int main() {
Graph merged;
for(auto& input: generate_file_data())
merge_into(std::istringstream(input), merged);
print_graph(merged);
}
如您所見,它會讀取許多(不同的)文件並將邊merged
到merged
圖中。
當然,在在線演示中我們沒有輸入文件,因此我在20個頂點( generate_file_data()
)中生成5個隨機邊緣的5個隨機圖。
有趣的是在merge_into
:
#include <boost/spirit/include/qi.hpp>
void merge_into(std::istream&& is, Graph& into) {
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
phx::function<edge_merge_f> merge_edges;
boost::spirit::istream_iterator f(is >> std::noskipws), l;
bool ok = qi::phrase_parse(f, l,
(qi::int_ >> *qi::int_) [ merge_edges(qi::_1, qi::_2, phx::ref(into)) ] % qi::eol,
qi::blank);
assert(ok);
}
這是處理精神的唯一代碼。 正如您所看到的,它根本不了解BGL。 這個邏輯留給了一個“回調”函數對象edge_merge_f
,這也很簡單:
struct edge_merge_f {
template <typename...> struct result { typedef void type; }; // for BOOST_RESULT_OF_USE_TR1:
template<typename V, typename Edges, typename G>
void operator()(V const& v, Edges const& edges, G& into) const {
for (auto e : edges)
if (!add_edge(v, e, into).second)
std::cout << "Duplicate edge: (" << v << "," << e << ")\n";
}
};
更新作為獎勵,通過將
EdgeCallback
作為boost::function
:EdgeCallback
版本傳遞給它來完全將merge_adjacencies
與Graph類型解耦 。 當然,效率會降低,但它通過保持分離來表明我的意思。
所以你有它。 這是我機器上的輸出(我沒有播種隨機引擎所以它是可重復的): Live On Coliru
Duplicate edge: (9,1)
Duplicate edge: (0,4)
0 --> 1 2 4 9
1 -->
2 -->
3 --> 1 7
4 --> 1
5 --> 1 6
6 --> 1 3 5
7 --> 5 6 8
8 --> 3
9 --> 1 2
如果更改Graph typedef以使用vecS
作為邊緣容器,則不必更改任何其他內容,結果是: Live On Coliru
0 --> 4 9 1 4 2
1 -->
2 -->
3 --> 7 1
4 --> 1
5 --> 1 6
6 --> 1 3 5
7 --> 5 6 8
8 --> 3
9 --> 1 2 1
[1]我想我把你與提升精神聯系在一起:“語義行為是邪惡的”? 之前:)
對於后代(還包括generate_file_data()
):
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
#include <sstream>
using namespace boost;
typedef adjacency_list<setS/*vecS*/, vecS, directedS> Graph;
std::vector<std::string> generate_file_data();
void merge_into(std::istream&& is, Graph& into);
int main() {
Graph merged;
for(auto& input: generate_file_data())
merge_into(std::istringstream(input), merged);
print_graph(merged);
}
////////////////////////////////
// Generating random test data
#include <boost/graph/random.hpp>
#include <boost/random.hpp>
std::vector<std::string> generate_file_data() {
std::vector<std::string> data;
mt19937 prng(42);
for (int i=0; i<5; ++i) {
std::ostringstream oss;
Graph g;
generate_random_graph(g, 10, 4, prng);
for (auto v : make_iterator_range(vertices(g))) {
oss << v << " ";
for (auto const& e : make_iterator_range(out_edges(v, g))) oss << target(e, g) << " ";
oss << "\n";
}
data.push_back(oss.str());
}
return data;
}
////////////////////////////////
// Merging edges
namespace {
struct edge_merge_f {
template <typename...> struct result { typedef void type; }; // for BOOST_RESULT_OF_USE_TR1:
template<typename V, typename Edges, typename G>
void operator()(V const& v, Edges const& edges, G& into) const {
for (auto e : edges)
if (!add_edge(v, e, into).second)
std::cout << "Duplicate edge: (" << v << "," << e << ")\n";
}
};
}
#include <boost/spirit/include/qi.hpp>
void merge_into(std::istream&& is, Graph& into) {
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
phx::function<edge_merge_f> merge_edges;
boost::spirit::istream_iterator f(is >> std::noskipws), l;
bool ok = qi::phrase_parse(f, l,
(qi::int_ >> *qi::int_) [ merge_edges(qi::_1, qi::_2, phx::ref(into)) ] % qi::eol,
qi::blank);
assert(ok);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.