如何借助Boost Property Maps为二叉树启用方括号运算符语法?
目标是在二叉树类中加入property maps,实现符合BGL风格的顶点属性访问语法:
using vertex_properties = std::string; using tree_type = binary_tree<vertex_properties, boost::no_property>; using vertex_descriptor = tree_type::vertex_descriptor; tree_type tree; vertex_descriptor a = add_vertex(tree, "a"); vertex_descriptor b = add_vertex(tree, "b"); assert(tree[a] == "a"); tree[a] = tree[b]; assert(tree[a] == "b");
已实现add_vertex函数,但无法启用方括号运算符语法。尝试在tree_type类中定义VertexManager类实例:
template<typename Graph, typename VertexProperty> struct VertexManager { using vertex_descriptor = typename Graph::vertex_descriptor; using vertex_hashmap_type = std::map<vertex_descriptor, VertexProperty>; vertex_hashmap_type _vertex_property_hashmap; boost::associative_property_map< vertex_hashmap_type > _vertex_property_map { _vertex_property_hashmap }; template<typename... Args> vertex_descriptor add_vertex_to_manager(Graph &g, Args&&... args) { vertex_descriptor key = add_vertex(g); VertexProperty value = { std::forward<Args>(args)...}; put(_vertex_property_map, key, value); return key; } const VertexProperty& operator [](vertex_descriptor v) const { return get(_vertex_property_hashmap, v); } VertexProperty & operator [](vertex_descriptor v) { return get(_vertex_property_hashmap, v); } };
但该方案无效,原因是Boost的get函数匹配到了const接口重载:
template <class T> inline const T& get(const T* pa, std::ptrdiff_t k) { return pa[k]; }
需要找到获取map中元素原位引用的方法。
问题出在你直接对std::map调用get,这会匹配到Boost中针对数组的get重载,而非针对property map的版本。你有两种可行的修正方式:
方式一:直接操作std::map
既然add_vertex_to_manager已经确保顶点描述符对应的属性存在于map中,你可以直接使用std::map的at()方法来获取引用,该方法在const和非const实例下分别返回const和非const引用:
const VertexProperty& operator [](vertex_descriptor v) const { return _vertex_property_hashmap.at(v); } VertexProperty & operator [](vertex_descriptor v) { return _vertex_property_hashmap.at(v); }
at()方法在键不存在时会抛出std::out_of_range异常,这符合BGL中访问无效顶点属性的错误语义。
方式二:使用Boost associative_property_map的get重载
如果你想坚持使用BGL的property map机制,需要显式调用针对boost::associative_property_map的get重载,而非直接操作原始map:
const VertexProperty& operator [](vertex_descriptor v) const { return boost::get(_vertex_property_map, v); } VertexProperty & operator [](vertex_descriptor v) { return boost::get(_vertex_property_map, v); }
这里必须显式指定boost::get,避免编译器匹配到其他无关的get重载。boost::associative_property_map的get方法会根据自身的const属性返回对应的引用类型。
额外注意
确保你的vertex_descriptor类型可以作为std::map的键(即支持<比较运算符),这是std::map的要求,也是BGL顶点描述符的常规约定。
内容的提问来源于stack exchange,提问作者WaterFox

