【发布时间】:2016-03-15 09:39:43
【问题描述】:
我有这样的结构(类型被简化以延续这一点),生活在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)(这就是[](const Region &reg, int index){…} 不起作用的原因)。
我实际上是通过在使用我之前提到的 lambda 时跟踪错误消息来提出解决方案的。 docs for std::upper_bound at cppreference.com写关于第四个论点:
比较函数对象(即满足 如果第一个参数是,则返回 true 小于秒。
比较函数的签名应该等同于 以下:
bool cmp(const Type1 &a, const Type2 &b);
签名不需要有const &,而是函数对象 不得修改传递给它的对象。Type1和Type2类型 必须使得T类型的对象可以隐式转换为Type1和Type2都可以,ForwardIt类型的对象可以是 取消引用,然后隐式转换为Type1和Type2。
Type1类型必须使得T类型的对象可以 隐式转换为Type1。Type2类型必须是这样的ForwardIt类型的对象可以被取消引用,然后隐式 转换为Type2。
(cppreference has been fixed 因为我发布了这个问题,谢谢@T.C.)
这里,T 是 std::upper_bound 的第三个参数,ForwardIt 是前两个参数的类型。这句话没有提到函数对象实际上是一个重载其operator() 以涵盖“正向”和“反向”情况的结构。
所以在写规则中,这是合法的,还是我的特定编译器/标准库组合 (g++ 5.3.1) 的产物?
我对 C++14 或 C++17 的特定答案感兴趣。
完整示例:
#include <algorithm>
#include <iostream>
#include <vector>
struct Region {
Region(int first, int count, int n):
first(first),
count(count),
n(n)
{
}
int first;
int count;
int n; // think struct Metadata
};
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;
}
};
int main() {
std::vector<Region> regions;
regions.emplace_back(0, 10, 1);
regions.emplace_back(10, 10, 2);
regions.emplace_back(20, 10, 3);
const int lookup = 10;
auto iter = std::upper_bound(
regions.begin(),
regions.end(),
lookup,
Comp());
// yes, I omitted error checking here, with error being iter == regions.begin()
std::cout << lookup << " is in region with n = " << (iter-1)->n << std::endl;
}
【问题讨论】:
-
啊,@T.C.,这也解释了我的困惑:-)。谢谢。
标签: c++ c++11 stl language-lawyer