【问题标题】:How passing arguments using std::mem_fun如何使用 std::mem_fun 传递参数
【发布时间】:2023-03-22 03:47:01
【问题描述】:

我想知道是否有办法使用 std::mem_fun 传递参数? 我想明确一点,我可以有尽可能多的参数和很多成员函数。
问题是我采用的是旧标准,我正在寻找一种完整的 stl 方式,因此即使我知道我可以轻松做到,也不允许将 boost 作为答案 =/

这是我想如何使用它的一个小例子:

#include <list>
#include <algorithm>

// Class declaration
//
struct Interface {
   virtual void run() = 0;
   virtual void do_something(int) = 0;
   virtual void do_func(int, int) = 0;
};

struct A : public Interface {
   void run() { cout << "Class A : run" << endl; }
   void do_something(int foo) { cout << "Class A : " << foo << endl; }
   void do_func(int foo, int bar) { cout << "Class A : " << foo << " " << bar << endl; }
};

struct B : public Interface {
   void run() { cout << "Class B : run" << endl; }
   void do_something(int foo) { cout << "Class B : " << foo << endl; }
   void do_func(int foo, int bar) { cout << "Class B : " << foo << " " << bar << endl; }
};

// Main
//
int main() {
   // Create A and B
   A a;
   B b;

   // Insert it inside a list
   std::list<Interface *> list;
   list.push_back(&a);
   list.push_back(&b);

   // This works
   std::for_each(list.begin(), list.end(), std::mem_fun(&Interface::run));

   // But how to give arguments for those member funcs ?
   std::for_each(list.begin(), list.end(), std::mem_fun(&Interface::do_something));
   std::for_each(list.begin(), list.end(), std::mem_fun(&Interface::do_func));
   return 0;
}

【问题讨论】:

    标签: c++ algorithm foreach


    【解决方案1】:

    通过std::bind1ststd::bind2nd 使用std::bind

    std::for_each(list.begin(), list.end(),
                  std::bind2nd(std::mem_fun(&Interface::do_something),1) // because 1st is this
                 );
    

    不幸的是,标准对两个参数版本没有帮助,您需要自己编写:

    struct MyFunctor
    {
        void (Interface::*func)(int,int);
        int         a;
        int         b;
    
        MyFunctor(void (Interface::*f)(int,int), int a, int b): func(f), a(a), b(b) {}
    
        void operator()(Interface* i){ (i->*func)(a,b);}
    };
    
    std::for_each(list.begin(), list.end(),
                  MyFunctor(&Interface::do_func, 1, 2)
                 );
    

    Lambda 版本

    最初的答案在 2012 年就很好,当时 Lambda 刚刚被添加到标准中,而且很少有编译器符合 C++11。现在 8 年后,大多数编译器都兼容 C++11,我们可以使用它来简化这些事情。

    // Binding 1 parameter
    std::for_each(list.begin(), list.end(),
                  [](auto act){act->do_something(1);})
    
    // Binding 2 parameters
    std::for_each(list.begin(), list.end(),
                  [](auto act){act->do_func(1, 2);})
    

    【讨论】:

    • 要找出std::bind1ststd::bind2nd 之间的区别,请参阅stackoverflow.com/a/6863747/5506988
    • @Mark 没有区别(除了明显的哪个参数绑定)。注意:这个问题是关于用两个参数调用“方法”,不幸的是这是不可能的,因为第一个参数用于对象,只有第二个参数可以用来绑定参数。注意:这与函数不同,因为它们不需要绑定对象。
    • @Mark 这也不再重要,因为 Lambdas 让我们现在可以更简单地做到这一点。
    • 把我带到这里的是一个需要一个参数的成员函数,但它是一个默认参数。它不会与std::for_each(list.begin(), list.end(),std::bind1st(std::mem_fun(&amp;Interface::do_something),1); 一起编译,只有 J.N. 的(最后一个答案)有效。但我仍然想知道为什么。 lambda 将解决我的问题,但我现在很好奇。
    【解决方案2】:

    你可以通过绑定:

    using std::placeholders::_1
    int a;
    std::for_each(list.begin(), list.end(), std::bind(&Interface::do_something, _1, a));
    

    【讨论】:

    • 他使用的是“旧标准”,即 98 或 03。这是 C++11。
    • @MSalters :注意到,不过,C++11 是去年的。
    【解决方案3】:

    std::bind1ststd::bind2nd。它们使用起来相当笨拙和难看,但如果你坚持只使用 C++03 中存在的东西而根本不添加任何东西,那么它们几乎就是所有可用的东西。

    编辑:当/如果我需要这样做时,我通常使用一个小的仿函数类而不是使用std::bind1st 和/或std::bind2nd。这最终与那些生成的内容没有太大区别,但是(IMO)它通常更具可读性。

    template<class T>
    class invoke_do_something { 
        int value;
    public:
        adder(int x) : value(x) {}
        void operator()(T &t) { 
            t.do_something(value);
        }
    };
    
    std::for_each(list.begin(), list.end(), invoke_do_something(1));
    

    然而,我自己的看法是,大多数时候这只是一种创可贴。它经常使用for_each 发生。我通常会发现,经过一番思考,我可以找到一个更合适的算法,它通常完全不需要这个订单上的任何东西。

    【讨论】:

    • 谢谢你的回答,你能举一个如何使用它的例子吗?我不能让它工作..
    • 我想我可以,但是 1)@LokiAstari 已经有了,所以不会增加太多,2)我自己从不使用它们。我很久以前就决定他们不值得麻烦。在我需要这种东西的(非常罕见的)情况下,我编写了一个小的仿函数类来处理它。值得庆幸的是,在 C++11 中,也很容易消除这种情况。
    • @kl94:我做了一些编辑,添加了一个我在觉得需要时通常采用的一般方法的示例。不过,我赶紧强调编辑的最后一点:大多数时候,更仔细的算法选择可以消除整个问题。
    • 非常感谢,我觉得如果我有很多成员函数,我将不得不创建与成员函数一样多的调用类 =/ 我寻找了一种更通用的方式,但是正如你所说,最新版本的 c++ 版本避免了我的问题。再次感谢您的帮助。
    【解决方案4】:

    由于c++20,你不需要std::bind和家人。您可以使用std::mem_fn 来执行此操作。请注意,std::mem_fun 不适用于 c++20

    #include <functional>
    #include <iostream>
    #include <string>
    
    struct Foo {
        void display_number(int i, char ch, std::string s) {
            std::cout << "number: " << i << " character: " << ch << " string: " << s << '\n';
        }
    };
    
    int main() {
        Foo f;
    
        auto print_num = std::mem_fn(&Foo::display_number);
        print_num(f, 42, 'a', "Hello!");
    }
    

    输出:

    number: 42 character: a string: Hello!
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-25
      • 2023-03-30
      • 2016-04-16
      • 1970-01-01
      • 2018-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多