2016-07-13 12 views
6

Mi sono imbattuto nella seguente funzione find_if.come funziona la funzione di bind per gli oggetti funzionali in C++

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

ho il dubbio che come bind (maggiore(), _ 1, x) e si legano (meno(), _ 1, y) vengono valutati e valori bool ritornano lì? Questo non funzionerà altrimenti come mostrato di seguito.

#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 
} 

Davvero curioso di sapere come i funtori sono chiamati all'interno della funzione di collegamento. Qualcuno può spiegare come funziona? Grazie in anticipo.

+0

Considerando che [ 'std :: logical_and'] (http://en.cppreference.com/w/cpp/utility/functional/logical_and) * valuta * i suoi argomenti, e non li chiama, il codice che mostri non funzionerà. –

+3

'bind' è molto particolare se invocato in modo ricorsivo. Si prega di prendere in considerazione solo l'utilizzo di lambda. – Yakk

+0

Ancora non completamente compreso. Ma dal tuo commento capisco che la funzione bind chiamerà internamente i funtori e il risultato è legato a logico_e? non sono sicuro :( –

risposta

5

Per comprendere questo, è necessario 1 st capire come bind, associa i suoi argomenti. Dato che g è il risultato di un'espressione bind che si chiama con: g(u1, u2, ... uM):

  • Se l'argomento arg memorizzato è di tipo std::reference_wrapper<T> (per esempio, std::ref o std::cref è stato utilizzato nella chiamata iniziale di impegnare) , quindi l'argomento vn nella chiamata std::invoke sopra è arg.get() e il tipo Vn nella stessa chiamata è T&: l'argomento memorizzato viene passato per riferimento nell'oggetto funzione invocato.
  • Se l'argomento memorizzato arg è di tipo std::is_bind_expression<T>::value == true (ovvero, un'altra espressione di bind è stata passata direttamente nella chiamata iniziale a bind), quindi esegue la composizione delle funzioni: invece di passare l'oggetto funzione che la sottoespressione di binding avrebbe return, la sottoespressione viene invocata arditamente e il suo valore di ritorno viene passato all'oggetto invokable esterno. Se la sottoespressione di bind ha degli argomenti segnaposto, vengono condivisi con il bind esterno (selezionato da u1, u2, ...). In particolare, l'argomento vn nella chiamata std::invoke in precedenza è arg(std::forward<Uj>(uj)...) e il tipo Vn nella stessa chiamata è std::result_of_t<T cv &(Uj&&...)>&& (la qualifica cv è la stessa di quella di g).
  • Se l'argomento arg memorizzato è di tipo T, per cui std::is_placeholder<T>::value != 0 significato, un segnaposto quale std::placeholders::_1, _2, _3, ... stata usata come argomento alla chiamata iniziale di impegnare), allora l'argomento indicato da il segnaposto (u1 per _1, u2 per _2, ecc) viene passato all'oggetto richiamabile: l'argomento vn nella chiamata std::invoke sopra è std::forward<Uj>(uj) e il tipo corrispondente Vn nella stessa chiamata è Uj&&.
  • Altrimenti, l'ordinario argomento arg memorizzato viene passato all'oggetto richiamabile come lvalue argomento: l'argomento vn nella std::invoke chiamata sopra è semplicemente arg e il tipo corrispondente Vn è T cv &, dove cv è lo stesso cv qualificazione come quello di g.

La chiave è nel 2 ° proiettile.Poiché le espressioni bind vengono richiamati al momento vincolante questo funziona:

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

Ma perché non c'è & operatore definito per le espressioni legano, questo non funzionerà:

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

Grazie per la spiegazione dettagliata Ora è chiaro –

+2

@PaulVarghese Amo il 'bind' per la sua chiarezza e per la familiarità che ho con esso dai tempi di' bind_1st' e 'bind_2nd'. , i compilatori hanno deffered l'ottimizzazione di 'bind' per l'ottimizzazione di lambdas.Questo è almeno vero per gcc: https://youtu.be/ZlHi8txU4aQ Non sono sicuro di dove Visual Studio atterra su tutto, ma penso che il clima generale dice preferisci lambda a 'bind's. –

Problemi correlati