boost :: dynamic_properties и объект неизменяемого графа

после реализации некоторого алгоритма с использованием BGL, я пытаюсь предоставить функции io, используя GraphML. Однако мне не удается собрать подходящий оператор<< это берет постоянную ссылку на График.

Вот пример, приведенный ниже:

// use bundled properties for vertices and edges
struct VertexProperty
{
double error;
};

typedef boost::adjacency_list< boost::setS, boost::setS, boost::undirectedS, VertexProperty> Graph;

typedef typename boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;

std::ostream& operator<<(std::ostream& os, const Graph& graph)
{
typedef std::map<vertex_descriptor, std::size_t> IndexMap;
IndexMap index_map;
boost::associative_property_map<IndexMap> index_properties(index_map);

std::size_t i = 0;
for (const vertex_descriptor& v : boost::make_iterator_range(boost::vertices(graph)))
index_properties[v] = i++;

boost::dynamic_properties dp;
typename boost::property_map<Graph, double VertexProperty::*>::const_type error_map = get(&VertexProperty::error, graph);

dp.property("error", error_map);

boost::write_graphml(os, graph,index_properties,dp);

return os;
}

int main()
{
Graph g;
std::cout << g <<std::endl;
}

Компиляция завершается неудачно с:

boost / property_map / property_map.hpp: 309: 44: ошибка: назначение
местоположение только для чтения ‘(&((Const
boost :: adj_list_vertex_property_map, double, const
двойной&двойной
VertexProperty :: *>&) pa)) -> boost :: adj_list_vertex_property_map :: operator [], double, const double&двойной
VertexProperty :: *> (к)»
static_cast (pa) [k] = v;

Насколько я понял из документа dynamic_properties, эти проверки только для чтения должны происходить во время выполнения (не является ли это одной из целей полного стирания типа). И, конечно, они должны потерпеть неудачу, если кто-то попытается изменить неизменяемое свойство. Но вызов wirte write_graphml () принимает константную ссылку на свойства динамической части и не должен ничего менять.

Чтобы сформулировать вопрос (ы):

  • Почему компиляция не удалась?
  • И как мне сделать это правильно?
  • Используя какую-то другую карту свойств (Да / Нет / Какой)?

Для (не) работающего примера @ coliru.stacked-crooked.com: Посмотреть здесь!

С Уважением,
Marti

3

Решение

Истинная проблема заключается в том, что категория карты свойств вершины выводится как LvaluePropertyMap (что это такое).

Тем не менее LvaluePropertyMap Концепция обещает быть надмножеством ReadablePropertyMap а также WritablePropertyMap, Это создает проблемы, когда const_type из свойств графа используются: они являются lvalues, но они не доступны для записи.

Единственное рабочее решение, которое я придумал, заключалось в том, чтобы обернуть тип карты свойств для отмены категории:

namespace detail {
template <typename Map>
struct readable_only_pmap : Map {
readable_only_pmap(Map map) : Map(map) { }

// overrule the category tag
typedef boost::readable_property_map_tag category;
};
}

Теперь вы можете использовать его так:

using pmap_t = typename boost::property_map<Graph, double VertexProperty::*>::const_type;
detail::readable_only_pmap<pmap_t> error_map = get(&VertexProperty::error, graph);

Хотя это почти то же самое, сейчас dynamic_properties::property обнаруживает, что карта доступна только для чтения, и не пытается сгенерировать положенных помощников (вместо этого будет сгенерировано исключение, если put попытка).

Полный код с демо-графиком:

Жить на Колиру

#include <iostream>
#include <string>
#include <vector>
#include <functional>

#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphml.hpp>
// #include <Eigen/Core>

// use bundled properties for vertices and edges
struct VertexProperty
{
double error;
// Eigen::Matrix<real,dim,1> location;
};

typedef boost::adjacency_list< boost::setS, boost::setS, boost::undirectedS, VertexProperty> Graph;

typedef typename boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;

namespace detail {
template <typename Map>
struct readable_only_pmap : Map {
readable_only_pmap(Map map) : Map(map) { }

// overrule the category tag
typedef boost::readable_property_map_tag category;
};
}

std::ostream& operator<<(std::ostream& os, const Graph& graph)
{
typedef std::map<vertex_descriptor, std::size_t> IndexMap;
IndexMap index_map;
boost::associative_property_map<IndexMap> index_properties(index_map);

std::size_t i = 0;
for (const vertex_descriptor& v : boost::make_iterator_range(boost::vertices(graph)))
index_properties[v] = i++;

using pmap_t = typename boost::property_map<Graph, double VertexProperty::*>::const_type;
detail::readable_only_pmap<pmap_t> error_map = get(&VertexProperty::error, graph);

boost::dynamic_properties dp;
dp.property("error", error_map);
boost::write_graphml(os, graph, index_properties, dp);

return os;
}

int main()
{
Graph g;
auto v1 = boost::add_vertex(VertexProperty{0.1}, g);
auto v2 = boost::add_vertex(VertexProperty{0.2}, g);
auto v3 = boost::add_vertex(VertexProperty{0.3}, g);
auto v4 = boost::add_vertex(VertexProperty{0.4}, g);
auto v5 = boost::add_vertex(VertexProperty{0.5}, g);

add_edge(v1,v2,g);
add_edge(v5,v2,g);
add_edge(v4,v2,g);
add_edge(v2,v3,g);
add_edge(v3,v4,g);
add_edge(v4,v1,g);

std::cout << g <<std::endl;
}

Вывод: (слегка переформатированный)

<?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="node" attr.name="error" attr.type="double" />
<graph id="G" edgedefault="undirected" parse.nodeids="free" parse.edgeids="canonical" parse.order="nodesfirst">
<node id="n0"> <data key="key0">0.1</data> </node>
<node id="n1"> <data key="key0">0.2</data> </node>
<node id="n2"> <data key="key0">0.3</data> </node>
<node id="n3"> <data key="key0">0.4</data> </node>
<node id="n4"> <data key="key0">0.5</data> </node>
<edge id="e0" source="n0" target="n1"> </edge>
<edge id="e1" source="n4" target="n1"> </edge>
<edge id="e2" source="n3" target="n1"> </edge>
<edge id="e3" source="n1" target="n2"> </edge>
<edge id="e4" source="n2" target="n3"> </edge>
<edge id="e5" source="n3" target="n0"> </edge>
</graph>
</graphml>
7

Другие решения


По вопросам рекламы [email protected]