C++ 我可以合法地使用带有重载运算符()的结构作为std::upper_bound的比较吗?

C++ 我可以合法地使用带有重载运算符()的结构作为std::upper_bound的比较吗?,c++,c++11,stl,language-lawyer,C++,C++11,Stl,Language Lawyer,我有这样的结构(类型经过简化以保留该点),生活在std::vector: struct Region { int first; int count; struct Metadata region_metadata; }; 在向量中,它们按第一个排序。如果添加第一个和计数,则获得下一个区域的第一个;所以基本上这个结构向量描述了连续数字范围的元数据 现在给定一个整数,我想查找元数据。在对区域进行排序时,我可以使用std::upper\u-bound。我是这样实施的: str

我有这样的结构(类型经过简化以保留该点),生活在
std::vector

struct Region {
    int first;
    int count;
    struct Metadata region_metadata;
};
在向量中,它们按
第一个
排序。如果添加
第一个
计数
,则获得下一个区域的
第一个
;所以基本上这个结构向量描述了连续数字范围的元数据

现在给定一个整数,我想查找元数据。在对区域进行排序时,我可以使用
std::upper\u-bound
。我是这样实施的:

struct Comp
{
    inline bool operator()(const Region &region, int index) const
    {
        return region.first < index;
    }

    inline bool operator()(int index, const Region &region) const
    {
        return index < region.first;
    }
};
现在这种情况发生了,因为
上限
可以在内部选择符合其要求的重载,因为它同时调用
Comp()(Region,int)
Comp()(int,Region)
(这就是
[](const Region®,int index){…
不起作用的原因)

实际上,我是通过跟踪使用前面提到的lambda时的错误消息来找到解决方案的。关于第四个论点:

比较函数对象(即满足 要求(比较)返回哪个​如果第一个参数为 不到第二个

比较函数的签名应与 以下:

bool cmp(const Type1 &a, const Type2 &b);
签名不需要有
常量&
,而是函数对象 不能修改传递给它的对象。类型
Type1
Type2
必须使类型为
T
的对象可以隐式转换为
Type1
Type2
,以及类型为
ForwardIt
的对象都可以 取消引用,然后隐式转换为
Type1
Type2

类型
Type1
必须使类型
T
的对象 隐式转换为
Type1
。类型
Type2
必须确保 类型为
ForwardIt
的对象可以取消引用,然后隐式引用 已转换为
类型2
。​

(自从我发布了这个问题,谢谢@T.C.)

这里,
T
std::upper_bound
的第三个参数,
ForwardIt
是前两个参数的类型。这段引文并没有提到函数对象实际上是一个结构,它重载了它的
操作符()
,以覆盖“正向”和“反向”情况

那么,在编写的规则中,这是合法的,还是我的特定编译器/标准库组合(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 &region, int index) const
    {
        return region.first < index;
    }

    inline bool operator()(int index, const Region &region) 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;
}
#包括
#包括
#包括
结构域{
区域(整数优先,整数计数,整数n):
第一(第一),,
数(数),,
n(n)
{
}
int优先;
整数计数;
int n;//思考结构元数据
};
结构组件
{
内联布尔运算符()(常量区域和区域,整数索引)常量
{
返回区域.first上限
可以在内部选择 符合其要求的重载,如它所称
Comp()(Region,int)
Comp()(int,Region)
(这就是
[](const Region®,int index){…}
不起作用的原因)

不,
upper\u-bound
只调用
Comp
的第二个重载。这正是您的(修复-谢谢@T.C.!)引用的内容:比较器的第一个参数始终是
upper\u-bound
的第三个参数。应该交换lambda的参数

在比较器中为
上界
/
下界
重载
运算符()
本质上是没有意义的,因为这些算法只会选择一个重载


operator()
应该像您在使用
equal_range
时所显示的那样重载,这样做是合法的,因为比较器(或任何与此相关的函子)的内部细节与库无关:您只需要确保顺序严格(即正确的语义)而且重载是明确无误的。

你说得很对。这可能会使这个问题偏离主题。我把lambda的论点搞砸了,并假设它们是正确的,所以我添加了重载,这当然使它起了作用。但由于我的假设是不正确的,所以结论也是正确的;它本来是有效的(事实上是有效的)(int,Region)重载。问题仍然存在。我们可以依靠算法函子的重载解析吗,也就是说,这对
equal_range
@sp2d足够公平。啊,@T.C.,这也解释了我的困惑:-)。谢谢。
#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 &region, int index) const
    {
        return region.first < index;
    }

    inline bool operator()(int index, const Region &region) 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;
}