ist nur Lassen vereinfachen, um den Unterschied zwischen Berücksichtigung
template <class C, class M> void f(C (M::*member)());
template <class C, class M> void g(C (M::*member));
In f
ist member
ein Zeiger auf eine Memberfunktion von M
Rückkehr Null Argumente nehmen und C
zurück. Wenn Sie es mit &B::func
aufgerufen haben, wird der Compiler M == B
und C == void
ableiten. Einfach.
In g
, member
ist nur ein Zeiger auf ein Mitglied M
des Typs C
. Aber in unserem Fall ist &B::func
eine Funktion. Die Auswirkung hier ist also nur den Zeiger fallen zu lassen. Wir leiten wieder M == B
ab, während C
wird void()
- jetzt C
ist ein Funktionstyp. Dies ist eine weniger spezialisierte Version von f
in dem es für mehr Arten von Mitgliedern ermöglicht. g
kann mit Funktionen übereinstimmen, die Argumente entgegennehmen, oder gegen Zeiger auf Mitglieder oder, relevant, gegen cv -qualifizierte Mitglied functinos.
Lassen Sie uns als Beispiel eine überladene Funktion betrachten und wie wäre es anders ableiten lassen (dies war das ursprüngliche Problem in Ihrer Frage, die bearbeitet seit wurde, ist aber immer noch interessant):
struct X {
void bar() { }
void bar(int) { }
};
Wenn wir tun:
f(&X::bar);
obwohl &X::bar
ist ein überlasteter Name, nur ein Spiel tatsächlich C (M::*)()
. Derjenige, der M == X
und C == void
hat. Es gibt einfach keine Möglichkeit, dass die Überladung von bar
unter Verwendung einer int
den Vorlagentyp entspricht. Dies ist einer der zulässigen Verwendungszwecke, einen überladenen Namen zu übergeben. Das folgert Geldbuße.
Wenn wir jedoch tun:
g(&X::bar);
Nun gibt es zwei perfekt vaild Abzüge. C
könnte sowohl void()
als auch void(int)
sein. Da beide gültig sind, ist der Abzug mehrdeutig und Sie können nicht kompilieren - mit einem Fehler, der dies nicht wirklich deutlich macht.
Sie jetzt zum Beispiel zurück:
call1(&B::func2, this); // Error: no matching member function for call to 'call2'
call2(&B::func2, this); // works
Die Art der &B::func2
ist void (B::*)() const volatile
. Da call1
auf einen Member-Funktionstyp ableitet, der keine Argumente akzeptiert und nicht cv-qualifiziert ist, schlägt der Typabzug einfach fehl.Es gibt keine C
oder M
, um diese Typen zu finden.
Allerdings ist der call2
Abzug in Ordnung, da es generischer ist. Es kann jeder Zeiger auf Mitglied entsprechen. Wir enden einfach mit C = void() const volatile
. Deshalb funktioniert das.
Ich wusste nicht einmal 'C (M :: * member)' ist gültige Syntax ... –
Der Punkt ist, dass 'call1' keine Funktionen mit cv-Qualifier akzeptieren, während' call2' das erlaubt. – Crossfire
Unzusammenhängend, aber warum sollte man 'std :: bind' verwenden, anstatt nur die Elementfunktion direkt aufzurufen? '(instance -> * member)();' –