【发布时间】:2015-08-29 01:24:31
【问题描述】:
我需要处理一组Foo 类型的对象列表,这些对象共享质量对应于Bar 的相同值。该列表是根据该质量预先排序的,所以我的想法是使用std::upper_bound 来查找后续组的开始位置。
Bar FooToBar(const Foo &foo);
// sorted so that FooToBar(foolist[0] <= FooToBar(foolist[1]) <= ...
std::list<Foo> foolist;
// find bounds of a group of Foo-s corresponding to someBar;
Bar someBar;
auto
groupBegin = foolist.begin(),
// find last item of foolist whose FooToBar() == someBar
groupEnd = std::upper_bound( foolist.begin(),
foolist.end(),
someBar );
这当然行不通,因为Foo 和Bar 不能直接比较。幸运的是,std::upper_bound 的重载需要一个额外的比较器参数:
groupEnd = std::upper_bound( foolist.begin(), foolist.end(), someBar, Compare);
问题是,我该如何写Compare()?这就是事情变得有趣的地方。 cppreference.com 说:
比较函数的签名应该等价于:
bool cmp(const Type1 &a, const Type2 &b);
签名不需要有const &,但函数对象不能修改传递给它的对象。 类型 Type1 和 Type2 必须使得 T 类型的对象可以隐式转换为 Type1 和 Type2,并且 ForwardIt 类型的对象可以取消引用,然后隐式转换为 Type1 和 Type2。
显然,我无法用Foo 和Bar 满足这些条件。但是,cplusplus.com 说的有些不同:
接受两个参数的二进制函数(第一个始终是 val,第二个是 ForwardIterator 指向的类型),并返回一个可转换为 bool 的值。
我可以使用它,所以:
bool Compare(const Bar &bar, const Foo &foo) { /* ... */ }
但是,这在 VS2013 和 g++ 中都无法编译:
/usr/lib/gcc/x86_64-pc-cygwin/4.9.2/include/c++/bits/predefined_ops.h:141:37: 错误:无法在参数传递中将“Foo”转换为“Bar”
奇怪的是,当我颠倒参数顺序时,它会编译、运行并按预期运行:
bool Compare(const Foo &foo, const Bar &bar) { /* ... */ }
所以看起来一个引用说一件事,另一个引用说另一件事,编译器接受的东西仍然不同。还是我误会了什么?
【问题讨论】:
-
请注意,比较的顺序或参数类型在
lower_bound和upper_bound之间是不同的。 -
是的,cppreference 的
Compare模板已损坏。许多算法确实要求比较器可以双向调用,但lower_bound和upper_bound不需要。 -
@T.C.也许它应该被简化为比较概念的链接,更精确
标签: c++ stl c++-standard-library