Domanda

Come la maggior parte dei programmatori ammiro e cerco di seguire i principi della programmazione di Literate, ma in C ++ mi trovo di routine a usare std :: pair , per compiti straordinari. Ma std :: pair è, IMHO, un vile nemico della programmazione alfabetica ...

Il mio punto è quando torno al codice che ho scritto un giorno o due fa, e vedo manipolazioni di un std :: pair (in genere come iteratore) Mi chiedo tra me e me ; che cosa significava iter- > first e iter- > second significa ??? " ;.

Suppongo che altri abbiano gli stessi dubbi quando guardano il loro codice std :: pair , quindi mi chiedevo, qualcuno ha trovato delle buone soluzioni per recuperare l'alfabetizzazione quando si usa std :: coppia ?

È stato utile?

Soluzione

Che ne dici di questo:

struct MyPair : public std::pair < int, std::string >
{
    const int& keyInt() { return first; }
    void keyInt( const int& keyInt ) { first = keyInt; }
    const std::string& valueString() { return second; }
    void valueString( const std::string& valueString ) { second = valueString; }
};

È un po 'prolisso, tuttavia l'utilizzo di questo nel codice potrebbe rendere le cose un po' più facili da leggere, ad esempio:

std::vector < MyPair > listPairs;

std::vector < MyPair >::iterator iterPair( listPairs.begin() );
if ( iterPair->keyInt() == 123 )
    iterPair->valueString( "hello" );

Oltre a questo, non riesco a vedere nessun proiettile d'argento che renderà le cose molto più chiare.

Altri suggerimenti

std :: pair è un buon modo per creare un " local " e tipo essenzialmente anonimo con colonne essenzialmente anonime; se stai usando una certa coppia su uno spazio lessicale così grande che devi nominare il tipo e le colonne, userei invece un semplice struct .

typedef std::pair<bool, int> IsPresent_Value;
typedef std::pair<double, int> Price_Quantity;

... ottieni il punto.

Puoi creare due coppie di getter (const e non) che restituiranno semplicemente un riferimento al primo e al secondo, ma saranno molto più leggibili. Ad esempio:

string& GetField(pair& p) { return p.first; }
int& GetValue(pair& p) { return p.second; }

Ti consentirà di ottenere il campo e valutare i membri da una determinata coppia senza dover ricordare quale membro detiene cosa.

Se prevedi di usarlo molto, potresti anche creare una macro che genererà quei getter per te, dati i nomi e i tipi: MAKE_PAIR_GETTERS (Field, string, Value, int) o simili. Rendere i getter semplici consentirà probabilmente al compilatore di ottimizzarli, quindi non aggiungeranno sovraccarico in fase di esecuzione; e l'uso della macro renderà semplicissimo creare quei getter per qualsiasi uso tu faccia delle coppie.

Potresti usare boost tuple, ma non alterano realmente il problema di fondo: il tuo davvero vuole accedere a ciascuna parte della coppia / tupla con un piccolo tipo integrale o vuoi codice più "letterato". Vedi questa domanda ho postato qualche tempo fa.

Tuttavia, boost :: opzionale è uno strumento utile che ho trovato sostituisce alcuni dei casi in cui coppie / tuple vengono propagandate come risposta.

Di recente mi sono trovato a usare boost :: tuple in sostituzione di std :: pair . Puoi definire gli enumeratori per ogni membro ed è quindi ovvio che cosa sia ogni membro:

typedef boost::tuple<int, int> KeyValueTuple;
enum {
  KEY
  , VALUE
};

void foo (KeyValueTuple & p) {
    p.get<KEY> () = 0;
    p.get<VALUE> () = 0;
}

void bar (int key, int value)
{
  foo (boost:tie (key, value));
}

A proposito, commenti positivi su se ci sono costi nascosti per l'utilizzo di questo approccio.

MODIFICA: rimuove i nomi dall'ambito globale.

Solo un breve commento sullo spazio dei nomi globale. In generale userei:

struct KeyValueTraits
{
  typedef boost::tuple<int, int> Type;
  enum {
    KEY
    , VALUE
  };
};

void foo (KeyValueTuple::Type & p) {
    p.get<KeyValueTuple::KEY> () = 0;
    p.get<KeyValueTuple::VALUE> () = 0;
}

Sembra che boost :: fusion leghi l'identità e il valore più vicini.

Come accennato da Alex, std :: pair è molto conveniente ma quando diventa confuso crea una struttura e usala allo stesso modo, dai un'occhiata a std :: pair code, non è così complesso.

Non mi piace neanche std :: pair come usato in std :: map, le voci della mappa avrebbero dovuto avere la chiave e il valore dei membri.
Ho persino usato boost :: MIC per evitarlo. Tuttavia, boost :: MIC ha anche un costo.

Inoltre, restituendo una coppia std :: pair si ottiene un codice non leggibile:

if (cntnr.insert(newEntry).second) { ... }

???

Ho anche scoperto che std :: pair è comunemente usato dai programmatori pigri che avevano bisogno di 2 valori ma non pensavano perché questi valori fossero necessari insieme.

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