Lors de l'utilisation de std::bind
pour lier une fonction membre, le premier argument est le pointeur objets this
. Cependant, cela fonctionne en passant l'objet à la fois comme pointeur et non.
Voir par exemple le programme suivant:
#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();
}
Clang et GCC le compilent sans se plaindre, et le résultat fonctionne pour les deux liaisons:
foo :: bar - 1 foo :: bar - 2
J'ai essayé de faire le tour de la spécification (section 20.8.9) mais c'est l'un des endroits où c'est loin d'être clair pour moi.
Un seul doit-il être correct, ou les deux sont-ils corrects?
Les deux sont corrects. 20.8.9.1.2 transmet au 20.8.2 pour décrire les exigences et l'effet de votre appel à bind
. 20.8.2 est:
20.8.2 Exigences [func.require]
1 Définissez INVOQUEZ
(f, t1, t2, ..., tN)
Comme suit:-
(t1.*f)(t2, ..., tN)
Lorsquef
est un pointeur vers une fonction membre d'une classeT
ett1
Est un objet de typeT
ou un référence à un objet de typeT
ou une référence à un objet d'un type dérivé deT
;-
((*t1).*f)(t2, ..., tN)
Lorsquef
est un pointeur vers une fonction membre d'une classeT
ett1
N'est pas l'un des types décrits dans l'élément précédent;-
t1.*f
LorsqueN == 1
Etf
est un pointeur vers les données de membre d'une classeT
ett1
Est un objet de typeT
ou une référence à un objet de typeT
ou une référence à un objet d'un type dérivé deT
;-
(*t1).*f
LorsqueN == 1
Etf
est un pointeur vers les données membres d'une classeT
ett1
N'est pas un des types décrits dans l'élément précédent;-
f(t1, t2, ..., tN)
dans tous les autres cas.
Les deux premières options permettent à la fois une référence et un pointeur.
La chose importante à noter ici est que la formulation ne pas vous limite aux simples pointeurs. Vous pouvez utiliser un std::shared_ptr
Ou un autre pointeur intelligent pour maintenir votre instance en vie pendant qu'elle est liée et cela fonctionnerait toujours avec std::bind
Car t1
Est déréférencé, quel qu'il soit ( étant donné, bien sûr, que c'est possible).
Pour ajouter à la bonne réponse (que les deux formulaires sont autorisés).
Je pense aux deux options de liaison en analogie avec la déclaration d'argument de fonction, qui peut être "passée par valeur" ou "passée par référence".
Dans le cas de f1
(aka passant my_foo
"par valeur") le résultat ne "voit" aucune modification apportée à my_foo
passé le point de liaison. Cela peut ne pas être souhaitable, surtout si my_foo
évolue. La liaison "par valeur" a un "coût" supplémentaire de (plusieurs) appels à un constructeur de copie.