c++ - 输出(对于 GraphViz)Boost Graph 顶点及其属性,使用带有私有(private)变量的类作为捆绑属性

标签 c++ boost graphviz boost-graph

我正在使用带有自定义类的 boost 有向图作为顶点的捆绑属性,并希望使用 graphviz 以 DOT 格式打印它。该类有一个私有(private)变量,我希望其值出现在 DOT 文件中。

演示我的问题的示例代码:

#include <iostream>
#include <boost/graph/directed_graph.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/property_map/transform_value_property_map.hpp>

class VertexClass
{
public:
    VertexClass() { id = 12; }
    VertexClass( int newId ) { id = newId; }
    int get_id() { return id; }
    void set_id( int newId ) { id = newId; }
private:
    int id;
};

typedef boost::directed_graph<VertexClass, boost::no_property> Graph;

int main(int,char*[])
{
    Graph g;

    Graph::vertex_descriptor v0 = g.add_vertex(3);
    Graph::vertex_descriptor v1 = g.add_vertex(5);
    Graph::vertex_descriptor v2 = g.add_vertex(6);

    boost::add_edge(v0,v1,g);
    boost::add_edge(v1,v2,g);

    //boost::write_graphviz(std::cout, g, ...);

    return 0;
}

期望的输出:

digraph G {
0[label=3];
1[label=5];
2[label=6];
0->1 ;
1->2 ;
}

(通过公开“id”并在代码下方运行获得)。

现在,“id”是私有(private)的,所以下面的代码(我在阅读其他类似问题时发现)对我不起作用:

boost::write_graphviz(std::cout, g, boost::make_label_writer(boost::get(&VertexClass::id, g)));

我想我必须使用访问器来获取 ID。经过一番搜索,我发现有人建议使用值转换属性映射 (make_transform_value_property_map)。

然后我找到this answer .但问题是,在那种情况下,该属性未定义为捆绑,而是使用枚举和 BOOST_INSTALL_PROPERTY。所以因为我没有这个方法提供的这些标签(而且我很难切换方法,因为我的实际代码更复杂),它对我不起作用(或者至少我不知道如何让它这样做)。

接下来,看完this answer我尝试了以下方法:

boost::write_graphviz(std::cout, g, boost::make_label_writer(boost::make_transform_value_property_map(&VertexClass::get_id, boost::get(boost::vertex_bundle, g))));

但我收到以下错误(下面的完整输出):

$ g++ -Wall -std=c++11 main.cpp
In file included from /usr/local/include/boost/graph/directed_graph.hpp:13:0,
                 from main.cpp:2:
/usr/local/include/boost/property_map/transform_value_property_map.hpp: In instantiation of ‘boost::transform_value_property_map<Func, PM, Ret>::reference boost::transform_value_property_map<Func, PM, Ret>::operator[](const key_type&) const [with Func = int (VertexClass::*)(); PM = boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>; Ret = int; boost::transform_value_property_map<Func, PM, Ret>::reference = int; boost::transform_value_property_map<Func, PM, Ret>::key_type = void*]’:
/usr/local/include/boost/property_map/property_map.hpp:303:54:   required from ‘Reference boost::get(const boost::put_get_helper<Reference, PropertyMap>&, const K&) [with PropertyMap = boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int>; Reference = int; K = void*]’
/usr/local/include/boost/graph/graphviz.hpp:85:56:   required from ‘void boost::label_writer<Name>::operator()(std::ostream&, const VertexOrEdge&) const [with VertexOrEdge = void*; Name = boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int>; std::ostream = std::basic_ostream<char>]’
/usr/local/include/boost/graph/graphviz.hpp:270:18:   required from ‘void boost::write_graphviz(std::ostream&, const Graph&, VertexPropertiesWriter, EdgePropertiesWriter, GraphPropertiesWriter, VertexID, typename boost::enable_if_c<boost::is_base_and_derived<boost::vertex_list_graph_tag, typename boost::graph_traits<Graph>::traversal_category>::value, boost::graph::detail::no_parameter>::type) [with Graph = boost::directed_graph<VertexClass, boost::no_property>; VertexPropertiesWriter = boost::label_writer<boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int> >; EdgePropertiesWriter = boost::default_writer; GraphPropertiesWriter = boost::default_writer; VertexID = boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, unsigned int, const unsigned int&, boost::vertex_index_t>; std::ostream = std::basic_ostream<char>; typename boost::enable_if_c<boost::is_base_and_derived<boost::vertex_list_graph_tag, typename boost::graph_traits<Graph>::traversal_category>::value, boost::graph::detail::no_parameter>::type = boost::graph::detail::no_parameter]’
/usr/local/include/boost/graph/graphviz.hpp:290:63:   required from ‘void boost::write_graphviz(std::ostream&, const Graph&, VertexPropertiesWriter, EdgePropertiesWriter, GraphPropertiesWriter, typename boost::enable_if_c<boost::is_base_and_derived<boost::vertex_list_graph_tag, typename boost::graph_traits<Graph>::traversal_category>::value, boost::graph::detail::no_parameter>::type) [with Graph = boost::directed_graph<VertexClass, boost::no_property>; VertexPropertiesWriter = boost::label_writer<boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int> >; EdgePropertiesWriter = boost::default_writer; GraphPropertiesWriter = boost::default_writer; std::ostream = std::basic_ostream<char>; typename boost::enable_if_c<boost::is_base_and_derived<boost::vertex_list_graph_tag, typename boost::graph_traits<Graph>::traversal_category>::value, boost::graph::detail::no_parameter>::type = boost::graph::detail::no_parameter]’
/usr/local/include/boost/graph/graphviz.hpp:309:38:   required from ‘void boost::write_graphviz(std::ostream&, const Graph&, VertexWriter, typename boost::enable_if_c<boost::is_base_and_derived<boost::vertex_list_graph_tag, typename boost::graph_traits<Graph>::traversal_category>::value, boost::graph::detail::no_parameter>::type) [with Graph = boost::directed_graph<VertexClass, boost::no_property>; VertexWriter = boost::label_writer<boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int> >; std::ostream = std::basic_ostream<char>; typename boost::enable_if_c<boost::is_base_and_derived<boost::vertex_list_graph_tag, typename boost::graph_traits<Graph>::traversal_category>::value, boost::graph::detail::no_parameter>::type = boost::graph::detail::no_parameter]’
main.cpp:30:166:   required from here
/usr/local/include/boost/property_map/transform_value_property_map.hpp:45:24: error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘((const boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int>*)this)->boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int>::f (...)’, e.g. ‘(... ->* ((const boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int>*)this)->boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int>::f) (...)’
     return f(get(pm, k));

我看到的每个问题/答案都是关于上述两种情况之一(将属性与公共(public)变量(例如结构)捆绑在一起,或老式的属性声明)。

我是 boost 图形库的新手,所以我想我可能错过了一些东西。但是我想不出一个解决方案(并且在 boost 的文档中真的迷路了),所以任何帮助将不胜感激。

最佳答案

transform_value_property_map 的包含向我表明您已接近解决方案。在这里:

boost::dynamic_properties dp;

首先,让我们声明您需要 graphviz 节点 ID 的固有顶点索引:

dp.property("node_id", get(boost::vertex_index, g));

现在我们想对 bundle 做一些事情,所以让我们获取整个 bundle 的属性映射:

auto vbundle = get(boost::vertex_bundle, g);

但是我们不能直接使用它。我们需要对其进行改造:

dp.property("label", 
        boost::make_transform_value_property_map([](VertexClass const& vd) {
            return vd.get_id();
            }, vbundle));

Note! I've made get_id() const constant to make this compile

现在写:

boost::write_graphviz_dp(std::cout, g, dp);

结果:

Live On Coliru

digraph G {
0 [label=3];
1 [label=5];
2 [label=6];
0->1 ;
1->2 ;
}

选择#1

在这种情况下,您可以使用更简单的方法:

Live On Coliru

dp.property("label", 
    boost::make_transform_value_property_map(std::mem_fn(&VertexClass::get_id), vbundle));

取而代之的是更灵活的 lambda

备选方案 #2:无准类

您似乎陷入了要求准类 (PDF) 的陷阱,它们没有任何值(value)。简化:

Live On Coliru

#include <boost/graph/directed_graph.hpp>
#include <boost/graph/graphviz.hpp>
#include <iostream>

struct VertexProps { int id; };
typedef boost::directed_graph<VertexProps> Graph;

int main() {
    Graph g;
    auto v1 = add_vertex({5}, g);

    add_edge(add_vertex({3}, g), v1, g);
    add_edge(v1, add_vertex({6}, g), g);

    boost::dynamic_properties dp;
    dp.property("node_id", get(boost::vertex_index, g));
    dp.property("label", get(&VertexProps::id, g));

    write_graphviz_dp(std::cout, g, dp);
}

正如您现在看到的那样,整个过程缩减为 20 行代码,并为您的顶点属性提供了一流的支持。

关于c++ - 输出(对于 GraphViz)Boost Graph 顶点及其属性,使用带有私有(private)变量的类作为捆绑属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50710922/

相关文章:

c++ - 任何调用 operator() 的 STL/boost 仿函数

c++ - 当我向 <vector> 添加对象时出现段错误

c++ - 使用正则表达式替换匹配项

python - 如何检查节点是否已存在于 Graphviz Python 中

c++ - 使用 IActiveScript 和 C++ 执行 cscript

c++ - 把 main 放在哪里,在那里写什么?

c++ - 了解 C 和 C++ 中的暂定定义

python - 试图从 scikit-learn 集成中打印出森林的决策树

graphviz - Graphviz 图的大小

c++ - 生命游戏继续边界