如何用模板类实现Boost RTree节点(cpp禁用Boost命名空间)
问题:封装Boost.Geometry RTree避免暴露命名空间
需求与现有代码
现有header.h和code.cpp两个文件,要求code.cpp中不能使用任何Boost命名空间,所有boost::geometry::...调用必须放在header.h中。计划实现两个模板类:Node和RTree,用户只需包含header.h即可通过这两个类使用RTree功能。
当前header.h代码:
template< class TT > class Node { using PointType = boost::geometry::model::d2::point_xy< TT >; using BoxType = boost::geometry::model::box< PointType >; using NodeType = std::pair< BoxType, std::string >; NodeType node; public: Node(){} template< class T > Node( const BBox< T > &box, const std::string nodeName ){ node = std::make_pair( BoxType{ PointType{ box.xLo(), box.yLo() }, PointType{ box.xHi(), box.yHi() } }, nodeName ); } }; template< class TT > class RTree { using RTreeType = boost::geometry::index::rtree< TT, boost::geometry::index::quadratic< 16 > >; RTreeType rtree; public: RTree(){} template< T > void insertBox( const BBox< T > &box, const std::string nodeName ) { rtree.insert( Node< T >( box, nodeName ) ); } template< T > void query( const BBox< T > &box, std::vector< Node< T > > &queryResult ) { rtree.query( boost::geometry::index::intersects( Node< T >( box, "" ) ), std::back_inserter( queryResult ) ); } };
编译错误信息
编译时出现以下关键错误:
error: could not convert 'boost::geometry::index::detail::indexable<Node<int>, false>::NOT_VALID_INDEXABLE_TYPE31::assert_arg()' from 'mpl_::failed************(boost::geometry::index::detail::indexable<Node<int>, false>::NOT_VALID_INDEXABLE_TYPE::************)(Node<int>)' to 'mpl_::assert<false>::type' {aka 'mpl_::assert<false>'} 31 | BOOST_MPL_ASSERT_MSG( | ^ | | | mpl_::failed************ (boost::geometry::index::detail::indexable<Node<int>, false>::NOT_VALID_INDEXABLE_TYPE::************)(Node<int>) ... error: could not convert 'boost::geometry::traits::point_type<Node<int> >::NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE45::assert_arg()' from 'mpl_::failed************ (boost::geometry::traits::point_type<Node<int> >::NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE::************)(mpl_::assert_::types<Node<int>, mpl_::na, mpl_::na, mpl_::na>)' to 'mpl_::assert<false>::type' {aka 'mpl_::assert<false>'} 45 | BOOST_MPL_ASSERT_MSG | ^ | | | mpl_::failed************ (boost::geometry::traits::point_type<Node<int> >::NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE::************)(mpl_::assert_::types<Node<int>, mpl_::na, mpl_::na, mpl_::na>) ... error: no type named 'type' in 'struct boost::geometry::traits::point_type<Node<int> >' 66 | >::type type; | ^~~~
问题原因与解决方案
这些错误的核心原因是:Boost.Geometry的RTree不知道如何从自定义的Node类型中提取用于空间索引的几何对象(也就是内部的BoxType),需要显式实现indexable特质,同时修正代码中的语法错误。
修改后的header.h代码
#include <boost/geometry.hpp> #include <boost/geometry/index/rtree.hpp> #include <vector> #include <string> #include <utility> // 假设BBox是用户自定义的边界框类,包含xLo(), yLo(), xHi(), yHi()方法 template<typename T> class BBox; template< class TT > class Node { public: using PointType = boost::geometry::model::d2::point_xy< TT >; using BoxType = boost::geometry::model::box< PointType >; using NodeType = std::pair< BoxType, std::string >; private: NodeType node; public: Node() = default; template< class T > Node( const BBox< T > &box, const std::string& nodeName ) : node( BoxType{ PointType{ static_cast<TT>(box.xLo()), static_cast<TT>(box.yLo()) }, PointType{ static_cast<TT>(box.xHi()), static_cast<TT>(box.yHi()) } }, nodeName ) {} // 提供获取内部边界框的接口,供indexable特质使用 const BoxType& get_box() const { return node.first; } // 提供获取节点名称的接口 const std::string& get_name() const { return node.second; } }; // 特化indexable特质,告诉RTree如何从Node对象中提取用于索引的几何框 namespace boost::geometry::index { template<typename TT> struct indexable<Node<TT>> { using result_type = typename Node<TT>::BoxType; const result_type& operator()(const Node<TT>& n) const { return n.get_box(); } }; } template< class TT > class RTree { private: using RTreeType = boost::geometry::index::rtree< Node<TT>, boost::geometry::index::quadratic< 16 > >; RTreeType rtree; public: RTree() = default; // 修正模板参数语法,添加typename template< typename T > void insertBox( const BBox< T > &box, const std::string& nodeName ) { rtree.insert( Node<TT>( box, nodeName ) ); } template< typename T > void query( const BBox< T > &box, std::vector< Node<TT> > &queryResult ) { // 直接构造查询用的Box,不需要构造空Node using BoxType = typename Node<TT>::BoxType; using PointType = typename Node<TT>::PointType; BoxType query_box( PointType{ static_cast<TT>(box.xLo()), static_cast<TT>(box.yLo()) }, PointType{ static_cast<TT>(box.xHi()), static_cast<TT>(box.yHi()) } ); rtree.query( boost::geometry::index::intersects( query_box ), std::back_inserter( queryResult ) ); } };
关键修改点说明
- 给Node类添加访问接口:增加
get_box()和get_name()方法,让外部(包括Boost的特质类)能访问内部的几何框和节点名称。 - 特化indexable特质:在
boost::geometry::index命名空间下特化indexable<Node<TT>>,告诉RTree调用get_box()来获取索引用的几何对象。 - 修正模板语法错误:原代码中
template< T >缺少typename关键字,改为template< typename T >。 - 优化查询逻辑:查询时直接构造RTree所需的
BoxType,不需要构造空的Node对象,避免不必要的构造开销。
内容的提问来源于stack exchange,提问作者gudé
相关产品推荐
相关产品推荐

