我们可以使用异构查找比较器对STL关联容器执行“部分匹配”搜索吗?

时间:2017-10-08 15:35:27

标签: c++ stl c++14

所以我一直在寻找对STL关联容器中异构查找的支持(自C ++ 14以来),并对我们可以做什么和不应该做什么感到困惑。
以下代码段

#include <algorithm>
#include <iostream>
#include <set>

struct partial_compare : std::less<>
{
    //"full" key_type comparison done by std::less
    using less<>::operator();

    //"sequence-partitioning" comparison: only check pair's first member
    bool operator ()(std::pair<int, int> const &lhs, int rhs) const
    {
        return lhs.first < rhs;
    }

    bool operator ()(int lhs, std::pair<int, int> const &rhs) const
    {
        return lhs < rhs.first;
    }
};

int main()
{
    //Using std::set's lookup
    {
        std::cout << "std::set's equal_range:\n";
        std::set <std::pair<int, int>, partial_compare> s{{1,0},{1,1},{1,2},{1,3},{2,0}};

        auto r = s.equal_range (1);

        for (auto it = r.first; it != r.second; ++it)
        {
            std::cout << it->first << ", " << it->second << '\n';
        }

        std::cout << "std::set's lower_bound + iteration on equivalent keys:\n";
        auto lb = s.lower_bound(1);

        while (lb != std::end(s) && !s.key_comp()(lb->first, 1) && !s.key_comp()(1, lb->first))
        {
            std::cout << lb->first << ", " << lb->second << '\n';
            ++lb;
        }
    }

    //Using algorithms on std::set
    {
        std::cout << "std::equal_range\n";
        std::set <std::pair<int, int>> s{{1,0},{1,1},{1,2},{1,3},{2,0}};

        auto r = std::equal_range (std::begin(s), std::end(s), 1, partial_compare{});
        for (auto it = r.first; it != r.second; ++it)
        {
            std::cout << it->first << ", " << it->second << '\n';
        }
    }
    return 0;
}

使用clang-5 / libc ++编译时生成以下输出:

std::set's equal_range:
1, 1
std::set's lower_bound + iteration on equivalent keys:
1, 0
1, 1
1, 2
1, 3
std::equal_range
1, 0
1, 1
1, 2
1, 3

使用gcc-7.1.0编译时的以下内容:

std::set's equal_range:
1, 0
1, 1
1, 2
1, 3
std::set's lower_bound + iteration on equivalent keys:
1, 0
1, 1
1, 2
1, 3
std::equal_range
1, 0
1, 1
1, 2
1, 3

通过阅读最初的N3465提案,我认为我在这里所做的应该是好的,在概念上与提案的初始示例中的相同:在查找期间的“部分匹配”,依赖于“序列划分的概念“ 现在,如果我理解正确,标准中最终的结果是N3657,但这似乎并未改变概念,因为它“只是”专注于确保异构查找成员模板仅在提供的比较器“is_transparent” 所以,我真的不明白为什么在clang / libc ++中使用std :: set的equal_range成员模板不能产生相同的gcc结果或等效的“lower_bound + scan”。 我错过了什么,并且以这种方式使用异构查找实际上违反了标准(然后clang是正确的,equal_rangelower_bound +扫描之间的差异可能是由于UB),或者是clang / libc ++错了?

编辑:在阅读了现在接受的答案后,我能够找到libc ++的相关bug report
关于libc ++和libstdc ++ here之间equal_range模板成员的行为差异,还有一个特定的问题,这是我在搜索时没找到的。 不确定是否应该删除或关闭它,因为我链接的那个没有接受的答案。

1 个答案:

答案 0 :(得分:6)

这是libc ++中的一个错误:它的equal_range implementation(在r315179)在找到“相等”元素时立即返回两个迭代器,即使是异构比较。