std::Funktion nicht zu unterscheiden, überladene Funktionen
Ich versuche zu verstehen, warum std::function
ist nicht in der Lage zu unterscheiden zwischen überladenen Funktionen.
#include <functional>
void add(int,int){}
class A {};
void add (A, A){}
int main(){
std::function <void(int, int)> func = add;
}
Im code oben gezeigt, function<void(int, int)>
entsprechen kann nur eine dieser Funktionen, und doch gelingt es nicht. Warum ist das so? Ich weiß, ich kann dies umgehen, indem mit einem lambda-Ausdruck oder eine Funktion Zeiger auf die eigentliche Funktion und die Speicherung der Funktion Zeiger in Funktion. Aber warum funktioniert das nicht? Ist das nicht der Kontext klar, welche Funktion will ich gewählt werden? Bitte helfen Sie mir zu verstehen, warum das so ausfällt, wie ich bin nicht in der Lage zu verstehen, warum template-matching versagt in diesem Fall.
Den compiler-Fehler, dass ich auf clang für diese sind wie folgt:
test.cpp:10:33: error: no viable conversion from '<overloaded function type>' to
'std::function<void (int, int)>'
std::function <void(int, int)> func = add;
^ ~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_03:1266:31: note:
candidate constructor not viable: no overload of 'add' matching
'std::__1::nullptr_t' for 1st argument
_LIBCPP_INLINE_VISIBILITY function(nullptr_t) : __f_(0) {}
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_03:1267:5: note:
candidate constructor not viable: no overload of 'add' matching 'const
std::__1::function<void (int, int)> &' for 1st argument
function(const function&);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_03:1269:7: note:
candidate template ignored: couldn't infer template argument '_Fp'
function(_Fp,
^
1 error generated.
BEARBEITEN - neben MSalters " Antwort, ich habe einige suchen auf dieses forum und fand den genauen Grund, warum dies nicht gelingt. Ich bekam die Antwort von Nawaz Antwort in diesem post.
Habe ich die Kopie eingefügt werden aus seiner Antwort hier:
int test(const std::string&) {
return 0;
}
int test(const std::string*) {
return 0;
}
typedef int (*funtype)(const std::string&);
funtype fun = test; //no cast required now!
std::function<int(const std::string&)> func = fun; //no cast!
Warum also std::function<int(const std::string&)>
funktioniert nicht, die Art und Weise funtype fun = test
funktioniert oben?
Nun, die Antwort ist, weil std::function
kann initialisiert werden mit einem Objekt, wie der Konstruktor ist templatized, die unabhängig von der template-argument übergeben std::function
.
gcc 4.8 und clang und Visual Studio 2013. Ich kann nach der compiler-Fehler, wenn dies erforderlich ist, obwohl Sie nicht sehr freundlich.
compiler-Fehler sind in der Regel nicht freundlich, aber Wert posting, es ist seltsam, dem wird dies hier nicht eindeutig, fast so, als wenn die Art der Klasse
A
ist irgendwie angesehen, als das gleiche wie int
, tritt der Fehler immer noch auftreten, wenn Sie erklären add
wie double
s?Ja. Es schlägt fehl, wenn ich die parameter-Typen zu verdoppeln, in der zweiten Funktion. Ich habe bearbeitet Sie die Frage, zählen die Fehler, ich bin immer auf clang.
ähnliche Frage und seine Antwort: stackoverflow.com/a/12500492/678093
InformationsquelleAutor MS Srikkanth | 2015-05-22
Du musst angemeldet sein, um einen Kommentar abzugeben.
Es ist für uns offensichtlich, welche Funktion Sie wollen gewählt werden, aber der compiler muß den Regeln von C++ nicht verwenden, geschickte Sprünge der Logik (oder auch nicht so klugen, wie in einfachen Fällen wie diesem!)
Den entsprechenden Konstruktor der
std::function
ist:ist eine Vorlage, die akzeptiert alle geben.
Den C++14-standard keine Einschränkung der Vorlage (seit LWG DR. 2132), so dass es:
was bedeutet, dass der compiler wird nur der Konstruktor aufgerufen werden, wenn
Functor
ist kompatibel mit dem call-Unterschrift desstd::function
(das istvoid(int, int)
in deinem Beispiel). In der Theorie sollte das bedeuten, dassvoid add(A, A)
ist kein tragfähiges argument und so "natürlich" Sie verwendenvoid add(int, int)
.Jedoch, der compiler kann nicht prüfen, was
f
Aufrufbar für argument-Typen ... " - Einschränkung, bis es weiß, die Art derf
, was bedeutet, es muss bereits disambiguated zwischenvoid add(int, int)
undvoid add(A, A)
vor es anwenden können, die Einschränkung, die erlauben würde, es ablehnen, eine dieser Funktionen!Also es gibt ein Huhn-und-ei-situation, was leider bedeutet, dass Sie benötigen, um den compiler durch Angabe genau die überlastung der
add
Sie verwenden möchten, und dann der compiler kann die Einschränkung und (nicht Redundant) entscheiden, dass es ist ein akzeptables argument für den Konstruktor.Es ist denkbar, dass wir wechseln konnten, C++, so dass in Fällen wie diesem alle die überladenen Funktionen sind getestet gegen die Einschränkung (so brauchen wir nicht zu wissen, was man zu testen bevor Sie es zu testen) und wenn nur einer lebensfähigen dann verwenden, aber das ist nicht, wie C++ funktioniert.
Der standard erfordert das trial-Abzüge, wenn das argument einer überlastung einstellen, aber nur, wenn der parameter ist der Zeiger auf Funktion Zeiger auf member-Funktion, oder-Funktion-Typ (siehe [temp.abziehen.call]/p6) nach stripping top-level-Lebenslauf-Qualifikations-und referenceness.
Es ist eine sehr interessante Idee, aber nur Abzug zu Versagen ist, dürfen in der Auswahl der überlastung, nicht substitution scheitern. So gibt es keine Möglichkeit, um das Mechanismus in einer solchen generischen Kontext als
std::function
.InformationsquelleAutor Jonathan Wakely
Während es offensichtlich ist, was Sie wollen, das problem ist, dass
std::function
keinen Einfluss überlast Auflösung von&add
. Wenn Sie zum initialisieren einer raw-Funktion Zeiger (void (*func)(int,int) = &add
), funktioniert es. Das ist, weil die Funktion Zeiger-Initialisierung ist ein Kontext, in dem überlast Auflösung erfolgt. Das Ziel geben Sie genau bekannt ist. Aberstd::function
nehmen fast jedes argument, das ist aufrufbar. Dass Flexibilität bei der Annahme von Argumenten bedeutet, dass Sie nicht tun können, überlast Auflösung auf&add
. Mehrere überladungen deradd
geeignet sein könnte.Einen expliziten cast funktioniert, d.h.
static_cast<void(*)(int, int)> (&add)
.Diese gewickelt werden kann in einer
template<typename F> std::function<F> make_function(F*)
die es erlauben würde, Sie zu schreibenauto func = make_function<int(int,int)> (&add)
int
implizit konvertierbarA
und zurück, dannstd::function<int(int,int)>
auch halten kannA add(A,A)
. Es ist diese Flexibilität, die überlastung macht nicht nur technisch, sondern auch logisch unmöglich.Huh. Ich habe geschrieben, so viele Funktion-oid-Klassen, die ich offenbar vergessen habe, dass
std::function<void(int,int)>
fehlt, ist einvoid(*)(int,int)
überlastung. Würde nicht eine solche überlastung harmlos und verursachen die oben genannten arbeiten?Sie würden noch zwei ctors von ` std::function<>
. How would you do overload resolution between the two, given
&add " (die zu diesem Zeitpunkt noch versucht, die Adresse eines überlast-set)? Also, Nein, die ctor überlast Auflösung hat zu geschehen, nachdem die überlast-Auflösung &hinzufügen und Umgekehrt, ist logisch unmöglich.außer es funktioniert. Ich wurde nicht gefragt, ob es funktioniert: ich weiß, es tut in der Praxis. Ich wurde gefragt, ob dort wo die Nachteile.
Die C++ - Stil heute schlägt das hinzufügen
std::function<F> function_from_ptr<F>(F* funptr)
da kannst du dann schreibenauto f = function_from_ptr<void()(int,int)>(&add)
. Das Muster dermake_shared
undmake_unique
.schlägtmake_function
aber zu sehen, stackoverflow.com/questions/27825559/...InformationsquelleAutor MSalters
Versuchen:
Adressen zu
void add(A, A)
undvoid add(int, int)
obvoiusly differes. Wenn Sie auf die Funktion von Namen ist es ziemlich imposible für compiler weiß, welche Funktion Adresse tun, die Sie benötigen.void(int, int)
hier ist nicht ein Hauch.InformationsquelleAutor W.F.
Andere Möglichkeit, damit umzugehen, ist eine generische lambda in C++14:
Schaffen, der eine lambda-Funktion, die aufgelöst wird, Dinge mit keine Mehrdeutigkeit.
Ich habe keine Argumente,
InformationsquelleAutor Germán Diago
Soweit ich sehen kann, es ist ein Visual Studio-problem.
c++11-standard (20.8.11)
aber VisualStudio nicht, dass die Spezialisierung
clang++ und g++ sind völlig in Ordnung, mit überlastung std::Funktionen
vorherigen Antworten erklären, warum VS nicht funktioniert, aber Sie nicht zu erwähnen, dass es VS' bug
Vor der Antwort erklären, schlecht VS Verhalten, das ist alles. Sie täuschen. Es ist so einfach wie, bitte, Lesen Sie standard
InformationsquelleAutor Dimitry Markman