简体   繁体   English

将成员函数作为比较运算符传递给C ++标准库算法

[英]Pass a member function as Compare operator for C++ standard library algorithm

In my code I have now something like 在我的代码中,我现在有类似

    Foo bar;
    std::unordered_set<Foo>::iterator minElement =
      std::min_element(std::begin(mySet),
                       std::end(mySet),
                       [&bar](Foo const &lhs, Foo const &rhs) {
                         return bar.myWeakLessOperator(lhs, rhs);
                       });

I wonder wether it exists a way to simplify it by passing directly the member function myWeakLessOperator (that is not static) instead of writing a lambda function just to make to call. 我想知道是否存在一种通过直接传递成员函数myWeakLessOperator (不是静态的)而不是编写仅用于调用的lambda函数来简化它的方法。

I would like to obtain something like 我想获得类似

    Foo bar;
    std::unordered_set<Foo>::iterator minElement =
      std::min_element(std::begin(mySet),
                       std::end(mySet),
                       /* something that rely to */ bar.myWeakLessOperator);

Any idea if it possible and how to do it ? 任何想法,如果可能的话,怎么做?

So you want to have a function object that represents a member function bound to a particular receiver. 因此,您需要一个函数对象来表示绑定到特定接收者的成员函数。 Unfortunately, there's nothing I could find in the standard or Boost that does that. 不幸的是,我在标准或Boost中找不到能做到这一点的东西。

What you can do is write your own fairly easily. 您可以做的就是相当轻松地编写自己的代码。

template <typename R, typename T>
struct member_function_binder {
    T *receiver;
    R T::*pmf;

    template <typename... Args>
    auto operator()(Args&&... args) {
        return (receiver->*pmf)(std::forward<Args>(args)...);
    }
};

template <typename R, typename T>
auto bind_member_function(R T::*pmf, T &receiver) {
    return member_function_binder<R, T>{&receiver, pmf};
}

Have a look at the live demo , I think this might be what you want. 看一下现场演示 ,我想这可能是您想要的。


Even more concise, you don't need to have a separate class member_function_binder if you return a lambda from bind_member_function like so: bind_member_function如果您从bind_member_function返回一个lambda,则无需再有一个单独的类member_function_binder

template <typename R, typename T>
auto bind_member_function(R T::*pmf, T &receiver) {
    return [pmf, &receiver](auto&&... args) {
        return (receiver.*pmf)(std::forward<decltype(args)>(args)...);
    };
}

Live demo 现场演示


Solution to pass a unary member function like Foo::compareTo(const Foo &rhs) , not what OP asked: 传递像Foo::compareTo(const Foo &rhs)这样的一元成员函数的解决方案,而不是OP要求的:

What you want is std::mem_fn ; 您想要的是std::mem_fn ; it's a wrapper that makes a member function pointer into a function object. 它是使成员函数指针变成函数对象的包装器。 You would use it like this: 您可以这样使用它:

auto min = std::min_element(
        begin(mySet), end(mySet), std::mem_fn(&Foo::myWeakLessOperator));

A possible solution is to use a struct that satisfies Compare inside Foo: 一个可能的解决方案是使用一个在Foo中满足Compare的结构:

class Foo 
{
public:
    struct WeakLessOperator
    {
        bool operator()(const Foo& a, const Foo& b)
        {
            // implementation - take care of meeting requirements of Compare
            return true;
        }
    };
    WeakLessOperator myWeakLessOperator;
};

Foo bar;

auto minElement =
    std::min_element(std::begin(mySet),
                     std::end(mySet),
                     bar.myWeakLessOperator);

you can use std::bind , or some other wrapper . 您可以使用std::bind或其他一些包装器

EXAMPLE: 例:

using namespace std::placeholders;
Foo bar;
std::unordered_set<Foo>::iterator minElement =
  std::min_element(std::begin(mySet),
                   std::end(mySet),
                   std::bind(&Foo::myWeakLessOperator, bar, _1, _2));

OR 要么

Foo bar;
std::unordered_set<Foo>::iterator minElement =
  std::min_element(std::begin(mySet),
                   std::end(mySet),
                   gnr::memfun<MEMFUN(Foo::myWeakLessOperator)>(bar));

The closest to what you want is maybe 最接近您想要的是

auto minElement =
  std::min_element(
            std::begin(mySet),
            std::end(mySet),
            mem_fun_functor(&Foo::myWeakLessOperator) 
  );

There is std::mem_fun (deprecated in c++11) and std::mem_fn both wrap a member function pointer, though both take a instance as parameter to invoke the member function. 尽管std::mem_fun (在c ++ 11中已弃用)和std::mem_fn都包装了一个成员函数指针,尽管它们都以实例作为参数来调用该成员函数。 If you want a functor that wraps the object also, i think you need to write your own: 如果您想要也包装对象的函子,我认为您需要编写自己的函子:

auto mem_fun_functor = 
    [&bar](decltype(&Foo::myWeakLessOperator) f){
        return [f,&bar](const Foo& a,const Foo& b) {
                  return (bar.*f)(a,b); 
               };
};

However, given that none of the answers is really much shorter or leading to cleaner code, I would consider to just use your first version with the lambda (unless you maybe have many different member functions that you want to use as comparator). 但是,鉴于所有答案都不是那么简短,也不会使代码更简洁,因此,我考虑将第一个版本与lambda一起使用(除非您可能有许多要用作比较器的成员函数)。

What do you actually mean by "simplifying" ? “简化”实际上是什么意思? You do need to specify the object you want to call the member function on, you need to specify how you want to forward the parameters. 您确实需要指定要在其上调用成员函数的对象,还需要指定要如何转发参数。 Thats basically all the lambda does. 那基本上就是lambda所做的所有事情。

Defering all this to a functor as for example above makes your code more complicated rather than simpler. 如上所述,将所有这些延迟给函子可以使您的代码更复杂而不是更简单。 In your first snippet anybody familiar with standard algorithms can look at that few lines of code and fully understand what is going on. 在您的第一个摘录中,熟悉标准算法的任何人都可以查看那几行代码,完全了解正在发生的事情。

Eventually it is a matter of style, and what you consider as readable, but being able to declare stuff in the most narrowest scope is one big advantage of using lambdas. 最终这是一个样式问题,以及您认为可读的问题,但是能够在最狭窄的范围内声明内容是使用lambda的一大优势。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM