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

时间:2016-03-15 09:39:44

标签: c++ c++11 stl language-lawyer

我有这样的结构(简化的类型以延续这一点),生活在std::vector

struct Region {
    int first;
    int count;
    struct Metadata region_metadata;
};

在向量中,它们按first排序。如果您添加firstcount,则会获得下一个区域的first;所以基本上这个结构向量描述了连续数字范围的元数据。

现在给定一个整数,我想查找元数据。由于区域已排序,我可以使用std::upper_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;
    }
};

当使用:

调用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 &reg, int index){…}
     

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

     

类型Type2必须是Type1类型的对象   隐式转换为T。类型Type1必须是这样的   类型Type2的对象可以被解除引用,然后隐式   转换为ForwardIt

(cppreference has been fixed因为我发布了这个问题,感谢@ T.C。)

这里,Type2T的第三个参数,std::upper_bound是前两个参数的类型。这句话并没有谈到函数对象实际上是一个结构,它重载了它的ForwardIt来覆盖&#34; forward&#34;和&#34;反向&#34;的情况。

所以在Rules-As-Written中,这是合法的,还是我特定的编译器/标准库组合(g ++ 5.3.1)的工件?

我对特定于C ++ 14或C ++ 17的答案感兴趣。

完整示例:

operator()

1 个答案:

答案 0 :(得分:9)

  

现在这恰好工作,因为upper_bound可以在内部选择   满足其要求的重载,因为它同时调用它们   Comp()(Region, int)Comp()(int, Region)(这是[](const Region &reg, int index){…}不起作用的原因。)

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

operator() / upper_bound的比较器内重载lower_bound本质上毫无意义,因为这些算法只能选择一个重载。

正如您在使用operator()时所显示的那样,

equal_range应该超载,并且这样做是合法的,因为比较器(或任何仿函数)的内部细节与此无关库:你只需要确保排序是严格的(即正确的语义)和过载是明确的。