Pregunta

Como la mayoría de los programadores admiro y trato de seguir los principios de la programación Literate, pero en C ++ me encuentro rutinariamente usando std :: pair , para miles de millones de tareas comunes. Pero std :: pair es, en mi humilde opinión, un enemigo vil de la programación alfabetizada ...

Mi punto es cuando vuelvo al código que escribí hace uno o dos días, y veo manipulaciones de un std :: pair (generalmente como un iterador) Me pregunto a mí mismo " ; ¿Qué significa iter- > first e iter- > second ??? " ;.

Supongo que otros tienen las mismas dudas cuando miran su código std :: pair , así que me preguntaba, ¿alguien ha encontrado algunas buenas soluciones para recuperar la alfabetización al usar std :: par ?

¿Fue útil?

Solución

¿Qué tal esto?

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

Es un poco detallado, sin embargo, usar esto en su código puede hacer que las cosas sean un poco más fáciles de leer, por ejemplo:

std::vector < MyPair > listPairs;

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

Aparte de esto, no puedo ver ninguna bala de plata que aclare las cosas.

Otros consejos

std :: pair es una buena manera de hacer un " local " y tipo esencialmente anónimo con columnas esencialmente anónimas; si está usando un par determinado en un espacio léxico tan grande que necesita nombrar el tipo y las columnas, en su lugar usaría un struct .

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

... entiendes el punto.

Puede crear dos pares de captadores (const y non) que simplemente devolverán una referencia al primero y al segundo, pero serán mucho más legibles. Por ejemplo:

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

Le permitirá obtener los miembros de campo y valor de un par determinado sin tener que recordar qué miembro tiene qué.

Si espera usar esto mucho, también podría crear una macro que generará esos captadores para usted, dados los nombres y tipos: MAKE_PAIR_GETTERS (Campo, cadena, Valor, int) más o menos. Hacer que los captadores sean sencillos probablemente le permitirá al compilador optimizarlos, por lo que no agregarán sobrecarga en tiempo de ejecución; y usar la macro facilitará la creación de esos captadores para cualquier uso que hagas de pares.

Podrías usar tuplas de impulso, pero en realidad no alteran el problema subyacente: ¿Tu realmente quieres acceder a cada parte de la pareja / tupla con un tipo integral pequeño, o quieres más código "alfabetizado". Consulte esta pregunta publiqué hace un tiempo.

Sin embargo, boost :: opcional es una herramienta útil que he encontrado reemplaza algunos de los casos en que los pares / tuplas se promocionan como respuesta.

Recientemente me encontré usando boost :: tuple como reemplazo de std :: pair . Puede definir enumeradores para cada miembro, por lo que es obvio qué es cada miembro:

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));
}

Por cierto, los comentarios son bienvenidos sobre si hay un costo oculto por usar este enfoque.

EDITAR: eliminar nombres del ámbito global.

Solo un comentario rápido sobre el espacio de nombres global. En general, usaría:

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

Parece ser el caso de que boost :: fusion vincula la identidad y el valor más cerca.

Como Alex mencionó, std :: pair es muy conveniente, pero cuando se vuelve confuso, cree una estructura y úsela de la misma manera, eche un vistazo a std :: pair código, no es tan complejo.

Tampoco me gusta std :: pair como se usa en std :: map, las entradas del mapa deberían haber tenido miembros clave y valor.
Incluso usé boost :: MIC para evitar esto. Sin embargo, boost :: MIC también tiene un costo.

Además, devolver un par std :: resulta en un código menos legible:

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

???

También descubrí que std :: pair es comúnmente usado por los programadores perezosos que necesitaban 2 valores pero no pensaban por qué estos valores se necesitaban juntos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top