通过与不同类型的值进行自定义比较来查找 std::set 的元素

2022-01-17 00:00:00 set c++ stl

考虑以下带有自定义比较器的 std::set 玩具示例:

Consider the following toy example of an std::set with a custom comparator:

#include <set>

struct A {
  A() : a(cnt++) {}
  const int a;
  static int cnt;
};

int A::cnt = 0;

struct comp {
  bool operator()(const A& left, const A& right)
  {
    return left.a < right.a;
  }
};

int main()
{
  std::set<A, comp> sa;
  for (int i = 0; i < 10; ++i) sa.insert(A());
  return 0;
}

请注意,A 不能简单地从整数创建.

Note that A cannot simply be created from an integer.

我想在 sa 中寻找具有 A::a 给定值的 AA 类型的临时对象,即我正在寻找类似的东西

I would like to look for an A with a given value of A::a in sa, without constructing a temporary object of type A, i.e. I am searching for something like

sa.find(4)

带有一个自定义比较器,允许直接将整数与 A 类型的对象进行比较.这可能吗?

with a custom comparator that allows for direct comparison of integers with objects of type A. Is that possible?

推荐答案

使用 C++14 你可以使用透明"比较器:

With C++14 you can utilize "transparent" comparator:

#include <iostream>
#include <set>
#include <type_traits>

class A
{
    public: explicit A() : a{cnt++} {}
    private: explicit A(int) = delete;
    public: const int a;
    private: static int cnt;
};

int A::cnt{};

class Comparator
{
    // this member is required to let container be aware that 
    // comparator is capable of dealing with types other than key
    public: using is_transparent = std::true_type;

    public: bool operator()(const int & left, const A& right) const
    {
        return left < right.a;
    }

    public: bool operator()(const A & left, const int& right) const
    {
        return left.a < right;
    }

    public: bool operator()(const A& left, const A& right) const
    {
        return left.a < right.a;
    }
};

int main()
{
    std::set<A, Comparator> sa{};
    for (int i{}; i < 10; ++i)
    {
        sa.emplace();
    }
    std::cout << sa.find(3)->a << std::endl;
    return 0;
}

在线编译器

::boost::intrusive::set:

#include <boost/intrusive/set.hpp>
#include <iostream>

namespace bi = ::boost::intrusive;

// hook contains set node data, supports various options, can be a member
class A: public bi::set_base_hook
<
    bi::link_mode<bi::link_mode_type::safe_link>
>
{
    public: explicit A() : a{cnt++} {}
    private: explicit A(int) = delete;
    public: const int a;
    private: static int cnt;
};

int A::cnt{};

class Comparator
{
    public: bool operator()(const int & left, const A& right) const
    {
        return left < right.a;
    }

    public: bool operator()(const A & left, const int& right) const
    {
        return left.a < right;
    }

    public: bool operator()(const A& left, const A& right) const
    {
        return left.a < right.a;
    }
};

int main()
{
    bi::set<A, bi::compare<Comparator>> sa{Comparator{}};
    for (int i{0}; i < 10; ++i)
    {
        sa.insert(*new A{}); // typically user manages object creation
    }
    // comparators may vary
    std::cout << sa.find(3, Comparator{})->a << std::endl;
    return 0;
}

在线编译器

相关文章