【问题标题】:std::set of MyElement with MyElement::SomeMethod as custom comparator以 MyElement::SomeMethod 作为自定义比较器的 MyElement 的 std::set
【发布时间】:2022-01-28 04:13:18
【问题描述】:

我有一个简单的MyElement 类,我想使用bool MyElement::SomeMethod(...) {...} 作为std::setMyElement 项目的自定义比较器。

我已经进行了研究,并且已经了解了一些替代解决方案,我在下面列出了这些解决方案。 我也知道如何更改比较器,例如使用std::greater 而不是默认的std::less,代码如下:

std::set<MyElement, std::greater<MyElement> > s;

我的确切问题是我想使用bool MyElement::SomeMethod(...) {...} 作为自定义比较器。 我想出的唯一解决方案类似于下面列表中的最后一个,即布尔函数的解决方案:

using Cmp = std::integral_constant<decltype(&MyElement::SomeMethod), 
                                   &MyElement::SomeMethod>;
std::set<MyElement, Cmp> my_set;

不过,此解决方案仅适用于 static MyElement::SomeMethod

我想知道非静态方法是否有类似或更简洁的方法。

替代解决方案列表:

C++20 方法

auto cmp = [](const MyElement& lhs, const MyElement& rhs) { return ... };
std::set<MyElement, decltype(cmp)> s;

C++11 方法

auto cmp = [](const MyElement& lhs, const MyElement& rhs) { return ... };
std::set<MyElement, decltype(cmp)> s(cmp);

函数而不是 lambda

 bool cmp(const MyElement& lhs, const MyElement& rhs) { return ...; }

然后

std::set<MyElement, decltype(cmp)*> s(cmp);

std::set<int, decltype(&cmp)> s(&cmp);

结构和操作符()

struct cmp {
    bool operator() (const MyElement& lhs, const MyElement& rhs) const {
        return ...
    }
};

然后

std::set<MyElement, cmp> s;

布尔函数

bool cmp(const MyElement& lhs, const MyElement& rhs) {
    return ...;
}

然后

#include <type_traits>
using Cmp = std::integral_constant<decltype(&cmp), &cmp>;
std::set<MyElement, Cmp> s;

【问题讨论】:

  • C++20也可以做std::set&lt;MyElement, decltype([](const MyElement&amp; lhs, const MyElement&amp; rhs) { return ... })&gt; s;
  • MyElement::SomeMethod 是静态的吗?
  • 那么integral_constant 技巧不起作用:gcc.godbolt.org/z/3e41zzsY4
  • 您在寻找typedef std::function&lt;bool(const MyElement&amp;, const MyElement&amp;)&gt; comparer; std::set&lt;MyElement,comparer&gt;{comparer{&amp;MyElement::SomeNonStaticMemberFunction}}; 吗?
  • @vaeVictis:是的,std::function 构造函数会将指向非静态成员函数的指针转换为第一个参数是目标对象的可调用对象,即 this在该成员函数内部,并且可调用的其余参数与该成员函数的实际参数匹配。

标签: c++ c++11 set custom-compare


【解决方案1】:

这有点主观,但对我来说,最简洁的选择是 struct + operator() 以匹配 std::less 的定义,std::set 的默认比较器。其他选项没有任何问题,但比较函子是一种常见模式且易于识别。

你也可以定义MyElement::operator&lt;,然后你就不需要单独传入一个比较器了。

【讨论】:

  • 我同意,我使用此解决方案或 lambda。我只是在探索替代方法。
  • 牢记可读性。这些方法中的大多数都不是惯用的,而且更难阅读。这并不一定会取消他们的资格,但遵循该语言常见模式的样式更容易让其他人一目了然。
【解决方案2】:

您可以使用std::mem_fn 绑定成员函数。

#include <functional>
#include <iostream>
#include <set>
#include <utility>

struct S {
  int i;

  bool cmp(const S& other) const { return i < other.i; }
};

// Define make function to avoid having to write out template types.
template <typename T, typename Cmp>
std::set<T, Cmp> make_set(Cmp&& cmp) {
  return std::set<T, Cmp>{std::forward<Cmp>(cmp)};
}

int main(int argc, char* argv[]) {
  auto s = make_set<S>(std::mem_fn(&S::cmp));
  s.emplace(S{0});

  std::cout << s.begin()->i << std::endl;
  return 0;
}

【讨论】:

  • 为你+1,但我的投票已锁定。请编辑您的答案,以便显示我的投票。话虽这么说,这个解决方案工作正常,但我只有一个问题。是否可以使用双参数 cmp?用lhs 代替thisrhs 代替other
  • @vaeVictis:您当然可以将参数命名为rhs 而不是other。但我无法理解比较器对三个对象(*thislhsrhs)的含义。不,您不能重命名 this 关键字,但您可以给它取别名。例如:bool cmp(const S&amp; rhs) const { const S&amp; lhs = *this; return lhs.i &lt; rhs.i; }。如果您只想有两个参数而没有this,则使用static 关键字。但是你的问题说你已经可以用静态成员函数来做,你特别问如何使用非静态成员函数(带有this指针)
  • @BenVoigt 我的问题,在这里和您的其他评论下都写得很糟糕,是由于您的解决方案功能签名和 Dev 的签名有点混淆。我阅读了其他一些文档,我可以说你们两个已经完全解开了我所有的疑虑。我很感激。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-15
  • 1970-01-01
  • 2014-02-05
  • 1970-01-01
  • 1970-01-01
  • 2016-07-07
相关资源
最近更新 更多