使用std :: bind和成员函数,对这个参数使用对象指针与否?

时间:2022-06-02 19:27:15

When using std::bind to bind a member function, the first argument is the objects this pointer. However it works passing the object both as a pointer and not.

当使用std :: bind绑定成员函数时,第一个参数是this指针的对象。但它可以将对象作为指针传递而不是。

See for example the following program:

例如,参见以下程序:

#include <iostream>
#include <functional>

struct foo
{
    void bar(int v) { std::cout << "foo::bar - " << v << '\n'; }
};

int main()
{
    foo my_foo;

    auto f1 = std::bind(&foo::bar, my_foo, 1);
    auto f2 = std::bind(&foo::bar, &my_foo, 2);

    f1();
    f2();
}

Both clang and GCC compiles this without complaints, and the result works for both binds:

clang和GCC都没有投诉地编译它,结果适用于两个绑定:

foo::bar - 1
foo::bar - 2

I have been trying to wrap my head around the specification (section 20.8.9) but it's one of the places where it's far from clear to me.

我一直试图围绕规范(第20.8.9节),但它是我不太清楚的地方之一。

Should only one be correct, or are both correct?

应该只有一个是正确的,还是都是正确的?

3 个解决方案

#1


47  

Both are correct. 20.8.9.1.2 forwards to 20.8.2 to describe the requirements and the effect of your call to bind. 20.8.2 is:

两者都是正确的。 20.8.9.1.2转发到20.8.2以描述要求和你的约束调用的效果。 20.8.2是:

20.8.2 Requirements [func.require]

1 Define INVOKE(f, t1, t2, ..., tN) as follows:

1定义INVOKE(f,t1,t2,...,tN),如下所示:

(t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T;

- (t1。* f)(t2,...,tN)当f是指向类T的成员函数的指针时,t1是类型为T的对象或对类型为T的对象的引用或对t的引用源自T的类型的对象;

((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of the types described in the previous item;

- ((* t1)。* f)(t2,...,tN)当f是指向类T的成员函数的指针时,t1不是前一项中描述的类型之一;

t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T;

- 当n == 1时,t1。* f,f是指向类T的成员数据的指针,t1是类型T的对象或对类型为T的对象的引用或对从中派生的类型的对象的引用吨;

(*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types described in the previous item;

- (* t1)。* f当N == 1且f是指向类T的成员数据的指针时,t1不是前一项中描述的类型之一;

f(t1, t2, ..., tN) in all other cases.

- 在所有其他情况下f(t1,t2,...,tN)。

The first two options allow both a reference and a pointer.

前两个选项允许引用和指针。

The important thing to notice here is that the wording does not limit you to plain pointers. You could use a std::shared_ptr or some other smart pointer to keep your instance alive while bound and it would still work with std::bind as t1 is dereferenced, no matter what it is (given, of course, that it's possible).

这里要注意的重要一点是,措辞并不限制你使用普通指针。您可以使用std :: shared_ptr或其他一些智能指针来保持您的实例在绑定时保持活动状态,它仍然适用于std :: bind,因为t1被取消引用,无论它是什么(当然,这是可能的) 。

#2


1  

To add to the correct answer (that both forms are allowed).

添加正确的答案(允许两种形式)。

I think of the two binding options in analogy with function argument declaration, which may be "passed by value" or "passed by reference".

我想到了与函数参数声明类似的两个绑定选项,它可以“通过值传递”或“通过引用传递”。

In the case of f1 (aka passing my_foo "by value") the result doesn't "see" any changes made to my_foo past the binding point. This may not be desired especially if my_foo evolves. "By value" binding has an additional "cost" of (several) calls to a copy constructor.

在f1(也就是通过值传递my_foo)的情况下,结果不会“看到”对my_foo的任何更改超过绑定点。如果my_foo发展,这可能是不可取的。 “按值”绑定具有对复制构造函数的(几个)调用的额外“成本”。

#3


-1  

There is a difference. As rytis put forward, passing by value doesn't see the changes made to my_foo. For example, in case my_foo is a class, passing by value doesn't see a change made to a member data of my_foo.

它们是有区别的。正如rytis提出的那样,传递值并不会看到对my_foo所做的更改。例如,如果my_foo是一个类,则传递值不会看到对my_foo的成员数据所做的更改。

#1


47  

Both are correct. 20.8.9.1.2 forwards to 20.8.2 to describe the requirements and the effect of your call to bind. 20.8.2 is:

两者都是正确的。 20.8.9.1.2转发到20.8.2以描述要求和你的约束调用的效果。 20.8.2是:

20.8.2 Requirements [func.require]

1 Define INVOKE(f, t1, t2, ..., tN) as follows:

1定义INVOKE(f,t1,t2,...,tN),如下所示:

(t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T;

- (t1。* f)(t2,...,tN)当f是指向类T的成员函数的指针时,t1是类型为T的对象或对类型为T的对象的引用或对t的引用源自T的类型的对象;

((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of the types described in the previous item;

- ((* t1)。* f)(t2,...,tN)当f是指向类T的成员函数的指针时,t1不是前一项中描述的类型之一;

t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T;

- 当n == 1时,t1。* f,f是指向类T的成员数据的指针,t1是类型T的对象或对类型为T的对象的引用或对从中派生的类型的对象的引用吨;

(*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types described in the previous item;

- (* t1)。* f当N == 1且f是指向类T的成员数据的指针时,t1不是前一项中描述的类型之一;

f(t1, t2, ..., tN) in all other cases.

- 在所有其他情况下f(t1,t2,...,tN)。

The first two options allow both a reference and a pointer.

前两个选项允许引用和指针。

The important thing to notice here is that the wording does not limit you to plain pointers. You could use a std::shared_ptr or some other smart pointer to keep your instance alive while bound and it would still work with std::bind as t1 is dereferenced, no matter what it is (given, of course, that it's possible).

这里要注意的重要一点是,措辞并不限制你使用普通指针。您可以使用std :: shared_ptr或其他一些智能指针来保持您的实例在绑定时保持活动状态,它仍然适用于std :: bind,因为t1被取消引用,无论它是什么(当然,这是可能的) 。

#2


1  

To add to the correct answer (that both forms are allowed).

添加正确的答案(允许两种形式)。

I think of the two binding options in analogy with function argument declaration, which may be "passed by value" or "passed by reference".

我想到了与函数参数声明类似的两个绑定选项,它可以“通过值传递”或“通过引用传递”。

In the case of f1 (aka passing my_foo "by value") the result doesn't "see" any changes made to my_foo past the binding point. This may not be desired especially if my_foo evolves. "By value" binding has an additional "cost" of (several) calls to a copy constructor.

在f1(也就是通过值传递my_foo)的情况下,结果不会“看到”对my_foo的任何更改超过绑定点。如果my_foo发展,这可能是不可取的。 “按值”绑定具有对复制构造函数的(几个)调用的额外“成本”。

#3


-1  

There is a difference. As rytis put forward, passing by value doesn't see the changes made to my_foo. For example, in case my_foo is a class, passing by value doesn't see a change made to a member data of my_foo.

它们是有区别的。正如rytis提出的那样,传递值并不会看到对my_foo所做的更改。例如,如果my_foo是一个类,则传递值不会看到对my_foo的成员数据所做的更改。