我有这样的结构(简化的类型以延续这一点),生活在std::vector
:
struct Region {
int first;
int count;
struct Metadata region_metadata;
};
在向量中,它们按first
排序。如果您添加first
和count
,则会获得下一个区域的first
;所以基本上这个结构向量描述了连续数字范围的元数据。
现在给定一个整数,我想查找元数据。由于区域已排序,我可以使用std::upper_bound
。我这样实现了它:
struct Comp
{
inline bool operator()(const Region ®ion, int index) const
{
return region.first < index;
}
inline bool operator()(int index, const Region ®ion) const
{
return index < region.first;
}
};
当使用:
调用std::upper_bound
时,这是有效的
auto iter = std::upper_bound(m_regions.begin(),
m_regions.end(),
index,
Comp());
现在这恰好工作,因为upper_bound
可以在内部选择符合其要求的重载,因为它调用Comp()(Region, int)
和Comp()(int, Region)
(这就是{{1}的原因不起作用)。
我实际上通过在使用前面提到的lambda时追踪错误消息来提出解决方案。关于第四个论点的docs for std::upper_bound at cppreference.com写:
比较函数对象(即满足该对象的对象) 比较的要求,如果第一个参数是,则返回 true 不到第二个。
比较函数的签名应该等同于 以下内容:
[](const Region ®, int index){…}
签名不需要bool cmp(const Type1 &a, const Type2 &b);
,而是函数对象 不得修改传递给它的对象。类型const &
和Type1
必须使Type2
类型的对象可以隐式转换为T
和Type1
都可以,Type2
类型的对象都可以 取消引用,然后隐式转换为ForwardIt
和Type1
。类型
Type2
必须是Type1
类型的对象 隐式转换为T
。类型Type1
必须是这样的 类型Type2
的对象可以被解除引用,然后隐式 转换为ForwardIt
。
(cppreference has been fixed因为我发布了这个问题,感谢@ T.C。)
这里,Type2
是T
的第三个参数,std::upper_bound
是前两个参数的类型。这句话并没有谈到函数对象实际上是一个结构,它重载了它的ForwardIt
来覆盖&#34; forward&#34;和&#34;反向&#34;的情况。
所以在Rules-As-Written中,这是合法的,还是我特定的编译器/标准库组合(g ++ 5.3.1)的工件?
我对特定于C ++ 14或C ++ 17的答案感兴趣。
完整示例:
operator()
答案 0 :(得分:9)
现在这恰好工作,因为
upper_bound
可以在内部选择 满足其要求的重载,因为它同时调用它们Comp()(Region, int)
和Comp()(int, Region)
(这是[](const Region ®, int index){…}
不起作用的原因。)
不,upper_bound
只调用Comp
的第二次重载。这正是你的(修复 - 感谢@ T.C。!)引用的内容:比较器的第一个参数始终是upper_bound
的第三个参数。应该交换lambda的参数。
在operator()
/ upper_bound
的比较器内重载lower_bound
本质上毫无意义,因为这些算法只能选择一个重载。
operator()
时所显示的那样, equal_range
应该超载,并且这样做是合法的,因为比较器(或任何仿函数)的内部细节与此无关库:你只需要确保排序是严格的(即正确的语义)和过载是明确的。