std :: bind如何与成员函数一起使用 [英] How std::bind works with member functions

查看:133
本文介绍了std :: bind如何与成员函数一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用std::bind,但是当我们将其与成员类函数一起使用时,仍然不知道它是如何工作的.

I'm working with std::bind but I still don't get how it works when we use it with member class functions.

如果我们具有以下功能:

If we have the following function:

double my_divide (double x, double y) {return x/y;}

我完全理解接下来的代码行:

I understand perfectly well the next lines of code:

auto fn_half = std::bind (my_divide,_1,2);               // returns x/2

std::cout << fn_half(10) << '\n';                        // 5

但是现在,在下面的代码中,我们具有绑定到成员函数的功能,我有一些疑问.

But now, with the following code where we have a bind to member function I have some questions.

struct Foo {
    void print_sum(int n1, int n2)
    {
        std::cout << n1+n2 << '\n';
    }
    int data = 10;
};

Foo foo;

auto f = std::bind(&Foo::print_sum, &foo, 95, _1);
f(5);

  • 为什么第一个参数是引用?我想得到一个理论上的解释.

    • Why is the first argument a reference? I'd like to get a theoretical explanation.

      第二个参数是对对象的引用,对我来说,这是最难理解的部分.我认为这是因为std::bind需要上下文,对吗?总是这样吗?当第一个参数是成员函数时,std::bind是否有某种实现需要引用?

      The second argument is a reference to the object and it's for me the most complicated part to understand. I think it's because std::bind needs a context, am I right? Is always like this? Has std::bind some sort of implementation to require a reference when the first argument is a member function?

      推荐答案

      当您说第一个参数是引用"时,您肯定会说第一个参数是 pointer ": &运算符获取对象的地址,并产生一个指针.

      When you say "the first argument is a reference" you surely meant to say "the first argument is a pointer": the & operator takes the address of an object, yielding a pointer.

      在回答这个问题之前,让我们先简单地退后一步,看看使用时第一次使用std::bind()

      Before answering this question, let's briefly step back and look at your first use of std::bind() when you use

      std::bind(my_divide, 2, 2)
      

      您提供了一个功能.当函数传递到任何地方时,它都会衰减为指针.上面的表达式等同于此表达式,显式采用地址

      you provide a function. When a function is passed anywhere it decays into a pointer. The above expression is equivalent to this one, explicitly taking the address

      std::bind(&my_divide, 2, 2)
      

      std::bind()的第一个参数是一个标识如何调用函数的对象.在上述情况下,它是指向类型为double(*)(double, double)的函数的指针.具有合适的函数调用运算符的任何其他可调用对象也可以这样做.

      The first argument to std::bind() is an object identifying how to call a function. In the above case it is a pointer to function with type double(*)(double, double). Any other callable object with a suitable function call operator would do, too.

      由于成员函数非常普遍,因此std::bind()支持处理指向成员函数的指针.使用&print_sum时,您仅获得指向成员函数(即void (Foo::*)(int, int)类型的实体)的指针.尽管函数名称隐式地衰减到指向函数的指针,即可以省略&,但对于成员函数(或数据成员)而言并非如此:要获得指向成员函数的指针,必须使用&.

      Since member functions are quite common, std::bind() provides support for dealing with pointer to member functions. When you use &print_sum you just get a pointer to a member function, i.e., an entity of type void (Foo::*)(int, int). While function names implicitly decay to pointers to functions, i.e., the & can be omitted, the same is not true for member functions (or data members, for that matter): to get a pointer to a member function it is necessary to use the &.

      请注意,指向成员的指针特定于class,但可以与该类的任何对象一起使用.即,它独立于任何特定对象. C ++没有直接获得直接绑定到对象的成员函数的直接方法(我认为在C#中,您可以通过使用具有已应用成员名称的对象来获得直接绑定到对象的函数;但是,距现在已有10多年的历史了我最后编写了一些C#).

      Note that a pointer to member is specific to a class but it can be used with any object that class. That is, it is independent of any particular object. C++ doesn't have a direct way to get a member function directly bound to an object (I think in C# you can obtain functions directly bound to an object by using an object with an applied member name; however, it is 10+ years since I last programmed a bit of C#).

      在内部,std::bind()检测到传递了指向成员函数的指针,并且很可能将其转换为可调用对象,例如,通过将std::mem_fn()与第一个参数一起使用.由于非static成员函数需要一个对象,因此分辨率可调用对象的第一个参数是对适当类的对象的引用或[smart]指针.

      Internally, std::bind() detects that a pointer to a member function is passed and most likely turns it into a callable objects, e.g., by use std::mem_fn() with its first argument. Since a non-static member function needs an object, the first argument to the resolution callable object is either a reference or a [smart] pointer to an object of the appropriate class.

      要使用指向成员函数的指针,需要一个对象.当使用指向带有std::bind()的成员的指针时,std::bind()的第二个参数相应地需要指定对象的来源.在您的示例中

      To use a pointer to member function an object is needed. When using a pointer to member with std::bind() the second argument to std::bind() correspondingly needs to specify when the object is coming from. In your example

      std::bind(&Foo::print_sum, &foo, 95, _1)
      

      生成的可调用对象使用&foo,即,指向foo(类型为Foo*)的指针作为对象. std::bind()足够聪明,可以使用任何看起来像指针的东西,可转换为适当类型的引用的任何东西(例如std::reference_wrapper<Foo>),或当第一个参数是指向对象的指针时将对象的[副本]用作对象.成员.

      the resulting callable object uses &foo, i.e., a pointer to foo (of type Foo*) as the object. std::bind() is smart enough to use anything which looks like a pointer, anything convertible to a reference of the appropriate type (like std::reference_wrapper<Foo>), or a [copy] of an object as the object when the first argument is a pointer to member.

      我怀疑,您从未见过指向该成员的指针-否则就很清楚了.这是一个简单的示例:

      I suspect, you have never seen a pointer to member - otherwise it would be quite clear. Here is a simple example:

      #include <iostream>
      
      struct Foo {
          int value;
          void f() { std::cout << "f(" << this->value << ")\n"; }
          void g() { std::cout << "g(" << this->value << ")\n"; }
      };
      
      void apply(Foo* foo1, Foo* foo2, void (Foo::*fun)()) {
          (foo1->*fun)();  // call fun on the object foo1
          (foo2->*fun)();  // call fun on the object foo2
      }
      
      int main() {
          Foo foo1{1};
          Foo foo2{2};
      
          apply(&foo1, &foo2, &Foo::f);
          apply(&foo1, &foo2, &Foo::g);
      }
      

      函数apply()仅获得两个指向Foo对象的指针和一个指向成员函数的指针.它调用每个对象指向的成员函数.这个有趣的->*运算符正在将成员的指针应用于对象的指针.还有一个.*运算符,该运算符将指向对象的成员的指针应用于对象(或者,就像它们的行为一样,对对象的引用).由于指向成员函数的指针需要一个对象,因此有必要使用此操作符来请求一个对象.在内部,std::bind()安排发生相同的事情.

      The function apply() simply gets two pointers to Foo objects and a pointer to a member function. It calls the member function pointed to with each of the objects. This funny ->* operator is applying a pointer to a member to a pointer to an object. There is also a .* operator which applies a pointer to a member to an object (or, as they behave just like objects, a reference to an object). Since a pointer to a member function needs an object, it is necessary to use this operator which asks for an object. Internally, std::bind() arranges the same to happen.

      当用两个指针和&Foo::f调用apply()时,其行为与在各个对象上调用成员f()的行为完全相同.同样,当使用两个指针和&Foo::g调用apply()时,其行为与在各个对象上调用成员g()时的行为完全相同(语义行为相同,但编译器可能会难得多)时间内联函数,通常在涉及到成员的指针时失败).

      When apply() is called with the two pointers and &Foo::f it behaves exactly the same as if the member f() would be called on the respective objects. Likewise when calling apply() with the two pointers and &Foo::g it behaves exactly the same as if the member g() would be called on the respective objects (the semantic behavior is the same but the compiler is likely to have a much harder time inlining functions and typically fails doing so when pointers to members are involved).

      这篇关于std :: bind如何与成员函数一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆