aumentare il problema lambda o fenice: usare std :: for_each per operare su ogni elemento di un contenitore

StackOverflow https://stackoverflow.com/questions/224704

  •  03-07-2019
  •  | 
  •  

Domanda

Ho riscontrato un problema durante la pulizia di un vecchio codice. Questa è la funzione:

uint32_t ADT::get_connectivity_data( std::vector< std::vector<uint8_t> > &output )
{
    output.resize(chunks.size());
    for(chunk_vec_t::iterator it = chunks.begin(); it < chunks.end(); ++it)
    {
        uint32_t success = (*it)->get_connectivity_data(output[it-chunks.begin()]);
    }
    return TRUE;
}

Quello che mi interessa fare è ripulire il ciclo for in modo che sia un'espressione lambda ma mi sono rapidamente bloccato su come avrei passato esattamente l'argomento corretto a get_connectivity_data. get_connectivity_data prende uno std :: vector per riferimento e lo riempie di alcuni dati. l'output contiene uno std :: vector per ogni "pezzo".

Fondamentalmente la mia conclusione è stata che è stato sostanzialmente più facile, più pulito e più breve lasciare il mio codice così com'è.

EDIT:

Quindi la risposta più vicina alla mia domanda come immaginavo sarebbe stata questa:

 std::for_each( chunks.begin(), chunks.end(), 
                   bind( &chunk_vec_t::value::type::get_connectivity_data, 
                         _1, 
                         output[ std::distance( _1, chunks.begn() ] 
                       )
                 );

Tuttavia quel codice non viene compilato, ho apportato alcune modifiche al codice per farlo compilare ma ho riscontrato 2 problemi:

  1. _ 1 è un ptr intelligente e std :: distance non ha funzionato su di esso, penso che avrei dovuto usare & amp; chunks [0] come inizio
  2. Poiché _ 1 è un puntatore intelligente, ho dovuto fare: & amp; chunk_vec_t :: value_ type :: ValueType :: get_ connectivity_ data che ha causato un arresto anomalo nel compilatore VC9 ...

La risposta relativa agli zip_ iteratori è stata buona fino a quando non ho letto di più e scoperto che per questo particolare utilizzo, la quantità di codice aggiuntivo necessaria era sostanziale (vincolante questo e quello, ecc.)

EDIT2:

Ho trovato una soluzione accettabile che è sia bassa sulla sintassi estranea che chiara, che ho pubblicato qui e sotto.

std::transform(chunks.begin(), chunks.end(), back_inserter(tmp), boost::bind(&ADTChunk::get_connectivity_data, _1) );
È stato utile?

Soluzione

Dopo un po 'di lavoro ho trovato questa soluzione:

std::transform(chunks.begin(), chunks.end(), back_inserter(tmp), boost::bind(&ADTChunk::get_connectivity_data, _1) );

Mi ha richiesto di cambiare get_connectivity_data per restituire std :: vector invece di prenderne uno come riferimento, e mi ha anche richiesto di cambiare gli elementi dei blocchi in modo che siano boost :: shared_ptr invece di Loki :: SmartPtr.

Altri suggerimenti

Penso che tu abbia ragione nel pensare che la cosa migliore da fare è lasciare il codice così com'è. Se hai difficoltà a capirlo quando (a) lo stai scrivendo e (b) capisci il problema esatto che stai cercando di risolvere, immagina quanto sarà difficile quando qualcuno arriverà tra 3 anni e deve comprendere sia il problema che la soluzione che hai scritto.

Senza vedere il codice per l'intera classe, è difficile determinare cosa funzionerà. Personalmente, penso che BOOST_FOREACH sia più pulito in questo caso, ma a scopo di riferimento, potrei provare a fare qualcosa del genere usando lambdas (nota che non posso testare la compilazione)

uint32_t ADT::get_connectivity_data( std::vector< std::vector<uint8_t> > &output )
{
    using namespace boost::lambda;

    output.resize( chunks.size() );

    std::for_each( chunks.begin(), chunks.end(), 
                   bind( &chunk_vec_t::value::type::get_connectivity_data, 
                         _1, 
                         output[ std::distance( _1, chunks.begn() ] 
                       )
                 );
    return TRUE;
}

In realtà non capisco cosa stai guidando per quanto riguarda la lambda, ma posso dare un paio di suggerimenti generali per la pulizia del codice che coinvolgono i contenitori STL.

Usa i typedef di tutti i tipi di container STL:

typedef std::vector<uint8_t> Chunks;
typedef std::vector<Chunks> Output;
uint32_t ADT::get_connectivity_data( Output &output )

Dato che stai parlando di usare Boost, usa Boost. foreach :

BOOST_FOREACH(chunk_vec_t::value_type &chunk, chunks)
  uint32_t success =
    chunk->get_connectivity_data(output[std::distance(&chunk, chunks.begin())]);

Pugnala al buio su "lambda" cosa:

typedef const boost::function2<uint32_t, chunk_vec_t::value_type, Chunks>
  GetConnectivity;
uint32_t ADT::get_connectivity_data(Output &output, GetConnectivity &getConnectivity)
{
  output.resize(chunks.size());
  BOOST_FOREACH(chunk_vec_t::value_type &chunk, chunks)
    uint32_t success =
      getConnectivity(chunk, output[std::distance(&chunk, chunks.begin())]);
  return TRUE;
}

Quindi potresti chiamarlo come:

get_connectivity_data(output,
  boost::bind(&chunk_vec_t::value_type::get_connectivity_data, _1, _2));

Quello che stai effettivamente facendo è eseguire un'operazione su due container in parallelo. Questo è ciò per cui è progettato boost :: zip_iterator.

Tuttavia, l'unico motivo necessario per elaborare i contenitori in parallelo è che Chunk :: get_connectivity_data accetta un parametro out. Se dovesse restituire per valore (utilizzando le eccezioni per segnalare errori), potresti semplicemente utilizzare un iteratore di inserimento.

Per qualche ragione, i principianti di STL insistono sempre nell'utilizzare un operatore vector :: iterator anziché l'operatore più leggibile (e a tempo costante) []. L'espressione it-chunks.begin () avrebbe dovuto dire all'autore originale che aveva già perso il gioco del programmatore di smartass e che aveva bisogno di un umile indice dopo tutto:

for (size_t i = 0, size = chunks.size(); i < size; ++i)
{
    chunks[i]->get_connectivity_data(output[i]);
} 

OP potrebbe anche considerare di perdere il codice di ritorno spurio e renderlo una funzione membro const.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top