Search code examples
c++boostgraphgraphvizboost-graph

Print a constified subgraph with write_graphviz()


I am struggling to dump a graph in a stream, where said graph is a constified version of a boost::subgraph.

I tried providing a property writer but basically it fails, because it seems to require a method boost::get(PropertyWriter, VertexDescriptor). Using the same methodology where the graph is not a subgraph works as expected.

As found here, I got to use a boost::dynamic_properties (see code below), but it fails when my graph is not writable (whereas the documentation indicates that the graph is taken as a constified reference).

Here is a simple example that I cannot get to work:

#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/subgraph.hpp>

struct VertexProperties
{
  std::string name;
};

int main()
{
  typedef boost::subgraph<
    boost::adjacency_list<
      boost::vecS, boost::vecS,
      boost::directedS,
      boost::property<boost::vertex_index_t, std::size_t, VertexProperties>,
      boost::property<boost::edge_index_t, std::size_t> > > Graph;

  Graph const g;

  boost::dynamic_properties dp;
  dp.property("name", boost::get(&VertexProperties::name, g));
  dp.property("node_id", boost::get(boost::vertex_index, g));
  boost::write_graphviz_dp(std::cout, g, dp);
}

Any hint is welcome! Thanks a lot,


EDIT

I forgot to mention what "failure" means in my case; here is the error when I try to compile:

error: passing ‘const std::basic_string’ as ‘this’ argument of ‘std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits, _Alloc = std::allocator, std::basic_string<_CharT, _Traits, _Alloc> = std::basic_string]’ discards qualifiers [-fpermissive]


Solution

  • As suggested, I reported this to be a bug in Boost.Graph (see the ticket).

    As a workaround, it appears that the underlying graph can be used instead of the subgraph, by accessing the member m_graph which is in the public scope.

    Here is how I got to workaround the problem, with a property writer:

    struct VertexProperties
    {
      std::string name;
    };
    
    template <typename Graph> struct prop_writer
    {
      prop_writer(Graph const& g): g_(g) {}
    
      template <typename Vertex> void operator()(std::ostream& out, Vertex v) const
      {
        out << g_[v].name;
      }
    
      Graph const& g_;
    }
    
    typedef boost::subgraph<
      boost::adjacency_list<
        boost::vecS, boost::vecS,
        boost::directedS,
        boost::property<boost::vertex_index_t, std::size_t, VertexProperties>,
        boost::property<boost::edge_index_t, std::size_t> > > Graph;
    
    Graph const g;
    
    // Note the use of g.m_graph here.
    boost::write_graphviz(std::cout, g.m_graph, prop_writer<Graph>(g));