boost::d ynamic_properties 和不可变的图形对象
boost::dynamic_properties and immutable graph object
在使用BGL实现一些算法后,我试图使用GraphML提供io函数。但是,我无法编译合适的运算符<<该运算符需要常量图引用。
下面是一个归结的例子:
// 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;
}
编译失败,并显示:
提升/property_map/property_map.hpp:309:44:错误:分配 只读位置 '(&((常量( 增强::adj_list_vertex_property_map,双倍,常量 双倍和,双倍 VertexProperty::*>&(pa((->boost::adj_list_vertex_property_map::operator[], double, const double&, double 顶点属性::*>(k(' static_cast(pa([k] = v;
据我了解dynamic_properties文档,这些只读检查应该在运行时进行(这不是整个类型擦除的目标之一(。当然,如果尝试修改不可变属性,它们应该会失败。但是对 wirte write_graphml(( 的调用需要对动态属性的 const 引用,并且不应该改变任何东西。
要陈述问题:
- 为什么编译会失败?
- 我该如何相应地做到这一点?
- 通过使用其他property_map(是/否/哪一个(?
有关(未(运行的示例@ coliru.stacked-crooked.com:请参阅此处!
问候马蒂
手头的真正问题是顶点属性映射的类别被推导出为LvaluePropertyMap
(确实如此(。
但是,LvaluePropertyMap
概念有望成为ReadablePropertyMap
和WritablePropertyMap
的超集。当使用图形属性的const_type
时,这会带来问题:它们是左值,但它们不可写。
我想出的唯一可行的解决方案是包装属性映射类型以否决该类别:
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>
- 正在寻找C++不可变的hashset/hashmap
- 如何在不销毁对象的情况下返回对象列表
- 当 std::move 与 C 样式数组或不移动对象时会发生什么
- 不可变的全局对象应该声明为"const my_result_t BLAH"还是"extern const my_result_t BLAH;"?
- 在C++中创建不可变对象的更好方法
- 区分对不可变对象和可变对象的常量引用
- 在 lambda 闭包中复制的 const 对象不可变
- 集合中的不可变对象(C++ 和 Qt)
- 创建不可变的 CFArray 对象 - Apple 示例不起作用
- 如何在Google V8 Javascript引擎中使对象不可变
- RAII 是否可以在不同步的情况下有效地在线程之间共享不可变对象
- jsoncpp:按名称访问JSON对象,返回可变引用,如果未找到则不创建对象
- C++中不可变对象的可变容器
- boost::d ynamic_properties 和不可变的图形对象
- 为什么我构建的临时对象const不可变
- 为什么我不能声明对可变对象的引用?( "reference cannot be declared mutable" )
- Java中除了字符串之外还有不可变对象吗?
- 如何在类中创建不可变的静态公共对象?
- 为什么要继续对不可变对象使用getter呢?
- c++ 11中线程间不可变对象的有效和安全传递