如何修改函数参数兼容std::vector与boost::range迭代器及相关问题
兼容std迭代器与Boost迭代器的函数参数设计方案
嘿,我来帮你理清这个问题的解决思路,毕竟在std迭代器和Boost迭代器之间做兼容确实容易让人头大:
一、不依赖模板兼容两种迭代器的方案
如果不想给函数加模板,类型擦除是唯一可行的路子——Boost库提供了boost::any_iterator来干这件事,它能把任何符合指定迭代器概念的具体迭代器(不管是std容器的,还是boost::join返回的)包装成统一的类型,对外只暴露迭代器的标准接口。
你可以把原来的函数参数改成这种包装后的迭代器类型:
#include <boost/iterator/any_iterator.hpp> typedef std::vector<Point> Points; // 定义统一的迭代器类型:指向const Point,前向遍历,返回const Point引用,差分为ptrdiff_t using ConvexHullIter = boost::any_iterator< const Point, boost::forward_traversal_tag, const Point&, std::ptrdiff_t >; // 修改后的函数 Points ConvexHull(ConvexHullIter first, ConvexHullIter last);
之后不管是传vec.cbegin()/vec.cend(),还是boost::join返回的迭代器,只要它们是前向迭代器且指向const Point,都能隐式转换成ConvexHullIter直接传入,完全不用改调用代码。
二、明确指定迭代器概念
别去碰boost::range_details里的东西!那些是Boost库的内部实现细节,公开接口里已经有更清晰的方式来指定迭代器概念:
- 用
boost::any_iterator时,第二个模板参数boost::forward_traversal_tag就明确了我们需要的是前向迭代器(如果需要随机访问迭代器,就换成boost::random_access_traversal_tag); - 如果改成接受范围而非两个迭代器,用
boost::any_range的话,第二个模板参数同样是遍历标签,用来指定迭代器概念,比如boost::any_range<const Point, boost::forward_traversal_tag>就表示这个范围的迭代器必须满足前向迭代器的要求。
这种方式比直接用内部类型安全得多,也更易读。
三、boost::any_range传递非const左值引用的问题
你遇到的错误原因很简单:std::vector<Point>和boost::any_range<Point, ...>是完全不同的类型,当你直接传vec给f(Range<Point> &points)时,会隐式生成一个Range<Point>临时对象,但C++不允许把非const左值引用绑定到临时对象。
解决办法有两个:
- 改成const引用或传值:如果函数不需要修改范围里的元素,直接把参数改成
const Range<Point>& points;如果允许传值,改成Range<Point> points——这两种情况都能直接传vec,因为临时对象可以绑定到const引用,或者被拷贝构造。 - 手动包装成Range对象:如果函数必须修改元素且要用非const引用,先把vector包装成
Range<Point>对象再传:
template<typename T> using Range = boost::any_range<T, boost::random_access_traversal_tag, T&, std::ptrdiff_t>; void f(Range<Point>& points); // 调用时 vector<Point> vec; Range<Point> wrapped_vec(vec); f(wrapped_vec);
注意这里要把any_range的第三个模板参数改成T&(默认是const T&),这样才能通过范围修改元素。
内容的提问来源于stack exchange,提问作者Anakhand
相关产品推荐
相关产品推荐

