boost :: dynamic_properties和不可变图对象 [英] boost::dynamic_properties and immutable graph object

查看:104
本文介绍了boost :: dynamic_properties和不可变图对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用BGL实现某种算法后,我尝试使用GraphML提供io函数.但是,我没有设法编译合适的运算符.需要一个const Graph参考.

after implementing some algorithm using the BGL, im trying to provide io functions using GraphML. However, i dont manage to compile a suitable operator<< that takes a const Graph reference.

这是一个精炼的例子:

// 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;
}

编译失败,并显示以下信息:

Compilation fails with:

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&,double 顶点属性:: *>(k)' static_cast(pa)[k] = v;

boost/property_map/property_map.hpp:309:44: error: assignment of read-only location '(&((const boost::adj_list_vertex_property_map, double, const double&, double VertexProperty::*>&)pa))->boost::adj_list_vertex_property_map::operator[], double, const double&, double VertexProperty::*>(k)' static_cast(pa)[k] = v;

据我了解dynamic_properties文档,那些只读检查应该在运行时进行(这不是整个类型擦除的目的之一).当然,如果人们试图修改不可变的属性,它们应该会失败.但是对wirte write_graphml()的调用将const引用为动力学属性,并且不应更改任何内容.

As far as i understood the dynamic_properties documentation, those read only checks are supposed to happen at runtime (Isn't this one of the aims of the whole type erasure). And of course they should fail if one tries to modify a immutable property. But the call to wirte write_graphml() takes a const ref to the dynamics properties and is not supposed to change anything.

陈述问题:

  • 为什么编译失败?
  • 我该如何正确地做到这一点?
  • 通过使用其他property_map(是/否/哪个)?

对于(未运行)示例@ coliru.stacked-crooked.com:在此处查看!

For a (not) running example @ coliru.stacked-crooked.com: See here!

关于, 马蒂

推荐答案

眼前的真正问题是,顶点属性映射的类别被推导出为LvaluePropertyMap(确实如此).

The true issue at hand is that the category of the vertex property map is being deduced as LvaluePropertyMap (which it is).

但是,LvaluePropertyMap概念有望成为ReadablePropertyMapWritablePropertyMap的超集.使用图属性的const_type时,这会带来问题:它们是左值,但不可写.

However, the LvaluePropertyMap concept promises to be a superset of ReadablePropertyMap and WritablePropertyMap. This poses problems when the const_type of the graph properties are used: they are lvalues, but they are not writable.

我想出的唯一可行的解​​决方案是包装属性映射类型以否决类别:

The only working solution I came up with was to wrap the property map type to overrule the category:

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;
        };
}

现在,您可以像这样使用它:

Now, you can use it like so:

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,则会引发异常).

Although it's nearly the same, now dynamic_properties::property detects that the map is readable only, and doesn't attempt to generate the put helpers (instead, an exception will be raised if a put is attempted).

在Coliru上直播

#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;
}

输出:(略有重新格式化)

Output: (slightly reformatted)

<?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>

这篇关于boost :: dynamic_properties和不可变图对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆