2015-09-23 17 views
8

Ho un foo che è un std::vector<int>. Rappresenta i valori di "bordo" per un insieme di intervalli.Un sostituto per std :: bind2nd

Ad esempio, se foo è {1, 3, 5, 7, 11}, gli intervalli sono 1-3, 3-5, 5-7, 7-11. Significativamente per me, questo equivale a 4 periodi. Nota che ogni periodo include il primo numero in un intervallo e non l'ultimo. Quindi nel mio esempio, 8 appare nel terzo periodo (a base zero). 7 appare anche nel 3 ° periodo. 11 e sopra non appaiono da nessuna parte. 2 appare nel periodo 0.

Data una bar che è un int, io uso

std::find_if(
    foo.begin(), 
    foo.end(), 
    std::bind2nd(std::greater<int>(), bar) 
) - foo().begin() - 1; 

di darmi il periodo che dovrebbe contenere bar.

Il mio problema: std::bind2nd è deprecato quindi dovrei refactoring. Qual è l'affermazione equivalente usando le funzioni aggiornate? std::bind non "rilascia" in modo ovvio.

+3

BTW, 'std :: distance (foo.begin(), std :: lower_bound (foo.begin(), foo.end(), bar)) - 1;' sembra più appropriato qui. – Jarod42

risposta

9

In C++ 11, è possibile utilizzare std::bind; semplicemente non è così evidente come usarlo:

#include <functional> 
using namespace std::placeholders; 
std::find_if(
    foo.begin(), 
    foo.end(), 
    // create a unary function object that invokes greater<int>::operator() 
    // with the single parameter passed as the first argument and `bar` 
    // passed as the second argument 
    std::bind(std::greater<int>(), _1, bar) 
) - foo().begin() - 1; 

La chiave è l'uso dell'argomento segnaposto, che vengono dichiarati nel std::placeholders namespace. std::bind restituisce un oggetto funzione che richiede un certo numero di parametri quando viene richiamato. I segnaposto utilizzati all'interno della chiamata a std::bind mostrano come gli argomenti forniti quando l'oggetto risultante viene richiamato si associano all'elenco di argomenti al chiamabile a cui si sta vincolando. Così, ad esempio:

auto op1 = std::bind(std::greater<int>(), _1, bar); 
op1(5); // equivalent to std::greater<int>()(5, bar) 

auto op2 = std::bind(std::greater<int>(), bar, _1); 
op2(5); // equivalent to std::greater<int>()(bar, 5) 

auto op3 = std::bind(std::greater<int>(), _2, _1); 
op3(5, bar); // equivalent to std::greater<int>()(bar, 5) 

auto op4 = std::bind(std::greater<int>(), _1, _2); 
op4(5, bar); // equivalent to std::greater<int>()(5, bar) 
5

bind versione sarebbe:

bind(std::greater<int>(), placeholders::_1, bar) 

ma penso, è più incoraggiati ad usare lambda, come in:

[bar](const int a){return bar < a;} 

Viene inoltre incoraggiato utilizzare le funzioni sovraccaricate begin/end anziché le chiamate di metodo. così sarebbe come:

find_if(begin(foo), end(foo), [bar](const int a){return bar < a;}) 
+0

Che cosa sono 'segnaposti :: _ 1'? –

+0

Potresti essere un angelo e mettere tutto insieme? ;-) –

+0

@ P45Imminente letteralmente _placeholders_; vedere [qui] (http://www.cplusplus.com/reference/functional/placeholders/?kw=placeholders) –

8

Che di andare direttamente da età della pietra (bind2nd) all'età del ferro con un C++ 14 lambda generica, bypassando l'età del bronzo (bind)?

std::find_if(foo.begin(), foo.end(), [&](auto const& elem) { 
    return elem > bar; 
}); 

E se l'ingresso è ordinato

std::lower_bound(foo.begin(), foo.end(), bar); 

Lambda leggono molto più facile e sono anche più facili da inline di std::bind expresions. Vedi per es. Lavevej's CppCon 2015 parlare.

+1

Sono d'accordo che questa è probabilmente la soluzione più facile da leggere, ma i tag della domanda includevano solo C++ 11. –

+0

@JasonR la mia filosofia è mostrare come vorrei codificarlo, a meno che non sostengano che non possono davvero usare C++ 14, e anche allora lo mostrerei se i risparmi sono abbastanza grandi :) La Q & A non è solo per il PO, ma per il pubblico in generale. Ma ho upvoted la tua risposta 'bind' :) – TemplateRex

+0

Abbastanza giusto; ciò ha senso. +1. –