It is straight forward to add edge weights to a graph as internal properties:
void InternalProperties()
{
std::cout << "InternalProperties()" << std::endl;
// Graph with internal edge weights
using EdgeWeightProperty = boost::property<boost::edge_weight_t, double>; // <tag, type>
using GraphWithInternalEdgeWeightsType = boost::adjacency_list<boost::setS, // out edge container
boost::vecS, // vertex container
boost::undirectedS, // directed or undirected
boost::no_property, // vertex properites
EdgeWeightProperty> // edge properties
;
// Create a graph object
GraphWithInternalEdgeWeightsType g(3);
// add two edges with edge weights
EdgeWeightProperty e1 = 5;
add_edge(0, 1, e1, g);
EdgeWeightProperty e2 = 3;
add_edge(1, 2, e2, g);
boost::property_map<GraphWithInternalEdgeWeightsType, boost::edge_weight_t>::type edgeWeightMap = get(boost::edge_weight_t(), g);
using edge_iter = boost::graph_traits<GraphWithInternalEdgeWeightsType>::edge_iterator;
std::pair<edge_iter, edge_iter> edgePair;
for(edgePair = edges(g); edgePair.first != edgePair.second; ++edgePair.first) {
std::cout << edgeWeightMap[*edgePair.first] << " ";
}
}
Now if I want to do the same thing and demonstrate using "external properties", I came up with this, but there is really no link at all back to the original graph:
void ExternalProperties()
{
std::cout << std::endl << "ExternalProperties()" << std::endl;
// Graph with external edge weights
using GraphWithExternalEdgeWeightsType = boost::adjacency_list<boost::setS, // out edge container
boost::vecS, // vertex container
boost::undirectedS> // directed or undirected
;
// Create a graph object
GraphWithExternalEdgeWeightsType g(3);
// add edges (without edge weights)
add_edge(0, 1, g);
add_edge(1, 2, g);
// create a map from edge_descriptors to weights and populate it
std::map<GraphWithExternalEdgeWeightsType::edge_descriptor, double> edgeWeightMap;
edgeWeightMap[boost::edge(0,1,g).first] = 5;
edgeWeightMap[boost::edge(1,2,g).first] = 3;
using edge_iter = boost::graph_traits<GraphWithExternalEdgeWeightsType>::edge_iterator;
std::pair<edge_iter, edge_iter> edgePair;
for(edgePair = edges(g); edgePair.first != edgePair.second; ++edgePair.first) {
std::cout << edgeWeightMap[*edgePair.first] << " ";
}
}
Is there any way to make something like get(boost::edge_weight_t(), g);
(from the internal example) return this map? Like to say g.setPropertyMap(boost::edge_weight_t, edgeWeightMap)
in this external example?
I'm not sure what the gain is, but perhaps this helps for inspiration:
#include <boost/graph/adjacency_list.hpp>
#include <boost/property_map/property_map.hpp>
#include <map>
#include <iostream>
namespace MyLib {
struct MyGraph : boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS> {
using base_type = boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS>;
using base_type::adjacency_list;
std::map<edge_descriptor, double> m_weights;
};
auto get(boost::edge_weight_t, MyGraph& g) { return boost::make_assoc_property_map(g.m_weights); }
auto get(boost::edge_weight_t, MyGraph const& g) { return boost::make_assoc_property_map(g.m_weights); }
}
namespace boost {
template <> struct graph_traits<MyLib::MyGraph> : graph_traits<adjacency_list<setS, vecS, undirectedS> > {};
template <> struct property_map<MyLib::MyGraph, edge_weight_t, void> {
using Traits = graph_traits<MyLib::MyGraph>;
using Edge = Traits::edge_descriptor;
using type = boost::associative_property_map<std::map<Edge, double> >;
using const_type = boost::associative_property_map<std::map<Edge, double> > const;
};
}
void ExternalProperties() {
std::cout << "ExternalProperties()" << std::endl;
// Graph with external edge weights
// Create a graph object
using Graph = MyLib::MyGraph;
Graph g(3);
// add edges (without edge weights)
add_edge(0, 1, g);
add_edge(1, 2, g);
// create a map from edge_descriptors to weights and populate it
auto edgeWeightMap = MyLib::get(boost::edge_weight, g);
edgeWeightMap[boost::edge(0, 1, g).first] = 5;
edgeWeightMap[boost::edge(1, 2, g).first] = 3;
using edge_iter = boost::graph_traits<Graph>::edge_iterator;
std::pair<edge_iter, edge_iter> edgePair;
for (edgePair = edges(g); edgePair.first != edgePair.second; ++edgePair.first) {
std::cout << edgeWeightMap[*edgePair.first] << " ";
}
}
int main() {
ExternalProperties();
}
I've not been able to avoid ambiguity with boost::get
in such a way that you can trust ADL to pick the "best" overload without namespace qualification.