我需要处理类型为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&amp; a,const Type2&amp; b);
签名不需要const&amp;,但是函数对象不能修改传递给它的对象。 类型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) { /* ... */ }
所以它看起来像一个引用说了一件事,其他引用说了别的东西,编译器接受了一些不同的东西。或者我误解了什么?
答案 0 :(得分:4)
您所指的是标准中的缺陷:#270。原来的措辞被认为是严格的(实际上,你提到了你的特定用例)。标准中的部分现在显示为[upper.bound]:
template<class ForwardIterator, class T> ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last, const T& value); template<class ForwardIterator, class T, class Compare> ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last, const T& value, Compare comp);
需要:
e
的元素[first,last)
应根据表达式!(value < e)
或!comp(value, e)
进行分区。
返回:i
范围内的最远迭代器[first,last]
,对于j
范围内的每个迭代器[first,i)
,以下相应条件成立:{ {1}}或!(value < *j)
。
在这两种情况下,comp(value, *j) == false
是value
的第一个参数,元素是第二个。所以以下是完全有效的代码:
comp
上面的内容适用于gcc 5.2(甚至4.6.4 - modulo lambda - 这是我最容易访问的lambda)和clang 3.6。
答案 1 :(得分:1)
如果您阅读了问题中引用的文档部分,您就会明白,除非存在从Bar
到Foo
的隐式转换,否则Compare
的两个版本都是不正确。一个版本有效的事实仅仅是一个幸运的巧合。使用不同的编译器可能很容易失败。