Search code examples
c++boost-graphgraphmldynamic-propertiesboost-property-map

How to write GraphML file to Boost Graph with custom graph_bundle Property?


I am not able to compile below , where I want to use graph_bundle property of boost graph.

struct VertexProps
{
    std::string VertexName;
};

struct EdgeProps 
{
    std::string edgeName;
};

struct GraphProps
{
    std::string name;
};

boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, VertexProps, EdgeProps, GraphProps> g;
g[boost::graph_bundle].name = "myGraphName";
boost::dynamic_properties dp;
dp.property("name", get(&GraphProps::name, g)); //compile error on this line
std::ofstream xmlFile("output.graphml");
boost::write_graphml(xmlFile, g, dp, true);
xmlFile.close();

I am getting beloe compile error:

<>/boost/graph/detail/adjacency_list.hpp:2646:29: error: forming reference to void
 2646 |         typedef value_type& reference;
      |                             ^~~~~~~~~
<>/boost/graph/detail/adjacency_list.hpp:2647:35: error: forming reference to void
 2647 |         typedef const value_type& const_reference;
      |                                   ^~~~~~~~~~~~~~~
<>/boost/graph/detail/adjacency_list.hpp:2651:13: error: forming reference to void
 2651 |             type;
      |             ^~~~
<>/boost/graph/detail/adjacency_list.hpp:2654:13: error: forming reference to void
 2654 |             const_type;
      |             ^~~~~~~~~~
test.cpp: In function ‘void writeGraph()’:
test.cpp:310:49: error: no matching function for call to ‘get(std::string GraphProps::*, Graph&)’
  310 |     dp.property("name", get(&GraphProps::name, g));
      |                                                 ^

It seems , boost graph library can't support custom property name , which can be used dynamic_properties for writing in graphml.


Solution

  • Graph properties in property maps are poorly documented. In fairness, they're also of limited use.

    You need to make an associative property map with key type G* (where G denotes your graph type).

    The simplest way would be to use make_constant_property_map:

    dp.property("name", boost::make_constant_property<G*>(get_property(g).name));
    

    See it Live On Coliru

    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/graphml.hpp>
    struct VertexProps { std::string VertexName; };
    struct EdgeProps   { std::string edgeName;   };
    struct GraphProps  { std::string name;       };
    
    int main() {
        using G = boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, VertexProps,
                                        EdgeProps, GraphProps>;
        G g;
    
        auto& gp = get_property(g);
        g[boost::graph_bundle].name = "myGraphName"; // or gp.name = "myGraphName"
    
        boost::dynamic_properties dp;
        dp.property("name", boost::make_constant_property<G*>(get_property(g).name));
    
        boost::write_graphml(std::cout, g, dp, true);
    }
    

    Printing

    <?xml version="1.0" encoding="UTF-8"?>
    <graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
      <key id="key0" for="graph" attr.name="name" attr.type="string" />
      <graph id="G" edgedefault="directed" parse.nodeids="canonical" parse.edgeids="canonical" parse.order="nodesfirst">
       <data key="key0">myGraphName</data>
      </graph>
    </graphml>