2014-12-15 17 views
9

voglio essere in grado di scrivere in C++ qualcosa di simile al seguente codice Python:Controllare se un elemento è in std :: initializer_list

if x in [1, 2, 3, 5] ... 

Per verificare se un elemento è contenuto in una serie di hard- valori codificati, definiti sul posto. Come questo:

if (in(x, {1, 2, 3, 5})) ... 

Ecco la possibile implementazione della funzione in:

template<class T> 
bool in(const T& x, std::initializer_list<T> c) 
{ 
    return std::find(c.begin(), c.end(), x) != c.end(); 
} 

La mia domanda è: ne ho veramente bisogno di scrivere questa funzione da solo? Ci sono implementazioni predefinite laggiù? Forse in boost? Ho controllato boost::contains, ma funziona solo con le stringhe.

+1

No, non c'è niente di meglio in C++. Ma hai davvero bisogno di quella (comoda) semantica Python in C++? –

+2

Come regola generale, Python è "batterie incluse" .... C++ è "crea le tue batterie da zero". –

+1

A proposito, perché non omettere le parentesi graffe e utilizzare un modello variadic? O è meno leggibile? – Columbo

risposta

2

Dal momento che una s countstd::set' restituisce solo 1 o 0 si potrebbe utilizzare che: (. E causare 5 stagioni di Lost)

if(set<int>{4, 8, 15, 16, 23, 42}.count(x)) 

Tenete a mente che i numeri nudi può creare confusione per il pubblico
Consiglierei di dichiarare i tuoi numeri come const e dare loro un nome significativo.

const std::initializer_list<int> finalCandidates{4, 8, 15, 16, 23, 42}; 

if(finalCandidates.end() != std::find(finalCandidates.begin(), finalCandidates.end(), x)) 
+0

È meglio dichiarare 'pippo' con' auto'. – Mikhail

+0

@Mikhail c'è un motivo per cui 'auto' sarebbe preferibile? –

+0

Sì. Il libro che ho citato nella domanda trascorre l'intero capitolo spiegando perché. – Mikhail

5

boost::algorithm::contains non funziona solo su stringhe, funziona su qualsiasi intervallo , ad esempio una sequenza che può produrre un iteratore di inizio e fine. Per trovare un singolo valore usarlo come segue:

auto l = {1,2,3,4}; 
auto l1 = {2};  // thing you want to find 
if(boost::algorithm::contains(l, l1)) { ... } 

è possibile eseguire la ricerca utilizzando solo la libreria standard, ma in questo modo è un po 'più dettagliato. Un paio di opzioni sono:

  1. utilizzando un lambda

    if(std::any_of(l.begin(), l.end(), 
           [](int i){ return i == 2; })) { ... } 
    
  2. utilizzando std::bind

    using std::placeholders::_1; 
    if(std::any_of(l.begin(), l.end(), 
           std::bind(std::equal_to<>(), 2, _1)) { ... } 
    

Live demo

noti che std::equal_to<>() è un'opzione solo per C++ 14. Per un compilatore C++ 11, utilizzare std::equal_to<int>().

+0

Oh, hai ragione. Ho provato a definire questi intervalli in posizione e la deduzione di tipo non è riuscita, poiché non è possibile dedurre il tipo di 'initializer_list'. Ecco perché non può essere utilizzato direttamente per il mio compito. Purtroppo. – Mikhail

+1

@Mikhail Sì, sfortunatamente la deduzione dell'argomento template non dedurrà un 'initializer_list' da una parentesi-init-list. Scrivere una funzione come quella che hai è la strada da percorrere se non vuoi creare temporaneamente 'initializer_list's. Oppure puoi specificare il tipo in modo esplicito: 'if (boost :: algorithm :: contains (std :: initializer_list {1,2,3,4}, std :: initializer_list {2}))' – Praetorian

+0

inserito nella nonsoluzione specificatore per la lambda – user1095108

1

Infatti lo STL non ha una semplice funzione std::contains(). Recentemente, c'era un discussion on reddit su questo argomento.

Sfortunatamente, ciò che ne è venuto fuori è che è considerato dannoso avere std::contains(), poiché incoraggia le persone a scrivere algoritmi lenti. Si pensi ad esempio di

if (!std::contains(my_set.begin(), my_set.end(), entry)) { 
    my_set.insert(insert); 
} 

Questo esempio di codice cerca essenzialmente per la corretta posizione due volte: una volta in contiene, e una volta per trovare il punto di inserimento.

A mio parere, sarebbe comunque molto utile avere std::contains(), ma finora nessuno era ancora convinto di scrivere una proposta.

Quindi, o spinta uso (come suggerito da altri in questa discussione), o scrivere la propria funzione che in sostanza già fatto :-)

+0

Non sono d'accordo con questa conclusione, ma grazie per la condivisione! – Mikhail

Problemi correlati