2016-07-13 5 views
6

Ich stieß auf die folgende find_if-Funktion.Funktionsweise der Bindefunktion für funktionale Objekte in C++

find_if (coll.begin(), coll.end(), 
      bind(logical_and<bool>(), 
        bind(greater<int>(),_1,x), bind(less<int>(),_1,y) 
       ) 
     ); 

Ich habe die Zweifel, dass, wie die bind (größer() _ 1, x) und bind (weniger() _ 1, y) werden ausgewertet und die Rückkehr Bool Werte gibt? Dies funktioniert nicht wie unten gezeigt.

#include <iostream> 
#include <functional> 

int main() 
{ 
    using namespace std::placeholders; 

    //auto fn = std::bind(std::greater<int>(), 5, _1); 
    //std::cout << fn(7) << std::endl; 
    //std::cout << typeid(fn).name() << std::endl; 

    auto fn1 = std::bind(std::greater<int>(),5,6); 
    auto fn2 = std::bind(std::less<int>(),7,5); 

    std::cout << std::bind(std::logical_and<bool>(), fn1, fn2)(); // how this works?? 
    std::cout << std::logical_and<bool>()(fn1, fn2)(); // Compilation error 
} 

Wirklich neugierig zu wissen, wie die Funktoren innerhalb der Bind-Funktion aufgerufen werden. Kann mir bitte jemand erklären, wie das geht? Danke im Voraus.

+0

Bedenkt man, dass [ 'std :: logical_and'] (http://en.cppreference.com/w/cpp/utility/functional/logical_and) * wertet * seine Argumente aus und ruft sie nicht an, der von Ihnen angezeigte Code funktioniert nicht. –

+3

'bind' ist sehr skurril, wenn rekursiv aufgerufen wird. Bitte denken Sie daran, nur Lambdas zu verwenden. – Yakk

+0

Noch nicht vollständig verstanden. Aber von deinem Kommentar verstehe ich, dass die Bindefunktion die Funktoren intern aufrufen wird und ihr Ergebnis an die logische_und gebunden ist? nicht sicher :( –

Antwort

5

Um dies zu verstehen, müssen wir 1 st verstehen, wie bind, bindet es Argumente. Da g das Ergebnis eines bind Ausdruck ist, der mit bezeichnet wird: g(u1, u2, ... uM):

  • Wenn das gespeicherte Argument arg vom Typ std::reference_wrapper<T> (beispielsweise std::ref oder std::cref wurde in dem anfänglichen Aufruf verwendet zu binden) , dann ist das Argument vn in dem std::invoke Aufruf oben arg.get() und der Typ Vn in demselben Aufruf ist T&: das gespeicherte Argument wird durch Verweis in dem aufgerufenen Funktionsobjekt übergeben.
  • Wenn das gespeicherte argument arg vom Typ T ist, für den std::is_bind_expression<T>::value == true (dh ein anderer Bindungsausdruck wurde direkt in den ersten Bindungsaufruf übergeben), führt bind die Funktion composition: anstelle des Funktionsobjekts aus, das der Bindungsunterausdruck würde return, der Teilausdruck wird eifrig aufgerufen, und sein Rückgabewert wird an das äußere aufrufbare Objekt übergeben. Wenn der Bind-Teilausdruck Platzhalter-Argumente hat, werden sie mit der äußeren Bindung geteilt (ausgewählt aus u1, u2, ...). Insbesondere ist das Argument vn in der obigen std::invoke-Anfrage arg(std::forward<Uj>(uj)...) und der Typ Vn in demselben Anruf ist std::result_of_t<T cv &(Uj&&...)>&& (cv-Qualifikation ist die gleiche wie die von g).
  • Wenn das gespeicherte Argument arg vom Typ T, für die std::is_placeholder<T>::value != 0, das heißt, ein Platzhalter wie std::placeholders::_1, _2, _3, ... wurde als das Argument für den ersten Anruf verwendet zu binden), dann wird das Argument angegeben durch der Platzhalter (u1 für _1, u2 für _2, usw.) an das aufrufbaren Objekt übergeben: das Argument vn im std::invoke Aufruf oben std::forward<Uj>(uj) ist und der entsprechende Typ Vn im gleichen Anruf Uj&&.
  • Andernfalls wird das gewöhnliche gespeicherte Argument arg an das aufrufbare Objekt als L-Wert Argument übergeben wird: das Argument vn im std::invoke oben Anruf einfach Arg- und der entsprechende Typ Vn ist T cv &, wo cv die gleiche cv-Qualifikation ist wie die von g.

Der Schlüssel ist in der 2 nd Kugel.Da sich die Binde Ausdrücke an Bindezeit aufgerufen werden, dies funktioniert:

std::cout << std::bind(std::logical_and<bool>(), fn1, fn2)() 

Aber weil es keine & Operator binden Ausdrücke definiert ist, wird dies nicht funktionieren:

std::cout << std::logical_and<bool>()(fn1, fn2)() 
+0

Danke für die ausführliche Erklärung. Jetzt ist es klar. –

+2

@PaulVarghese Ich liebe 'bind' für seine Klarheit und für die Vertrautheit, die ich damit von zurück in den Tagen' bind_1st' und 'bind_2nd' habe. Aber ehrlich gesagt , Compiler haben die Optimierung von 'bind' für die Optimierung von Lambdas entschärft.Dies gilt zumindest für gcc: https://youtu.be/ZlHi8txU4aQ Ich bin nicht sicher, wo Visual Studio auf alles landet, aber ich denke, das allgemeine Klima sagt bevorzuge Lambdas zum 'Bind's. –

Verwandte Themen