Pregunta

¿Por qué nadie parece usar tuplas en C++, ni el Impulsar la biblioteca de tuplas ¿O la biblioteca estándar para TR1?He leído mucho código C++ y muy raramente veo el uso de tuplas, pero a menudo veo muchos lugares donde las tuplas resolverían muchos problemas (generalmente devuelven múltiples valores de funciones).

Las tuplas te permiten hacer todo tipo de cosas interesantes como esta:

tie(a,b) = make_tuple(b,a); //swap a and b

Sin duda es mejor que esto:

temp=a;
a=b;
b=temp;

Por supuesto, siempre puedes hacer esto:

swap(a,b);

Pero, ¿qué pasa si quieres rotar tres valores?Puedes hacer esto con tuplas:

tie(a,b,c) = make_tuple(b,c,a);

Las tuplas también hacen que sea mucho más fácil devolver múltiples variables de una función, lo que probablemente sea un caso mucho más común que intercambiar valores.Usar referencias a valores de retorno ciertamente no es muy elegante.

¿Hay grandes inconvenientes para las tuplas en los que no estoy pensando?Si no es así, ¿por qué rara vez se utilizan?¿Son más lentos?¿O es simplemente que la gente no está acostumbrada a ellos?¿Es una buena idea utilizar tuplas?

¿Fue útil?

Solución

Debido a que no es todavía estándar. Cualquier cosa no estándar tiene un obstáculo mucho mayor. Piezas de Boost se han hecho populares porque los programadores estaban clamando por ellos. (Hash_map salta a la mente). Pero mientras tupla es práctico, no es una victoria tan aplastante y claro que la gente se moleste con él.

Otros consejos

Una respuesta cínica es que muchas personas programan en C++, pero no comprenden ni utilizan la funcionalidad de nivel superior.A veces es porque no están permitidos, pero muchos simplemente no lo intentan (o ni siquiera entienden).

Como ejemplo sin impulso:¿Cuántas personas usan la funcionalidad que se encuentra en <algorithm>?

En otras palabras, muchos programadores de C++ son simplemente programadores de C que utilizan compiladores de C++, y quizás std::vector y std::list.Ésa es una de las razones por las que el uso de boost::tuple No es más común.

La sintaxis tupla C ++ puede ser un poco más detallada que la mayoría de la gente le gustaría.

Considere lo siguiente:

typedef boost::tuple<MyClass1,MyClass2,MyClass3> MyTuple;

Así que si quieres hacer un uso extensivo de tuplas que o bien obtener typedefs tupla todas partes o se obtiene molesto nombres de los tipos largos en todas partes. Me gusta tuplas. Los uso cuando sea necesario. Pero por lo general es limitado a un par de situaciones, como un índice N-elemento o cuando se utiliza Multimapas para atar los pares gama de iterador. Y es por lo general en un alcance muy limitado.

Es todo muy feo y hacky mirando si se compara con algo así como Haskell o Python. Cuando C ++ 0x llegue aquí y tenemos los 'auto' tuplas de palabras clave comenzarán a mirar mucho más atractivo.

La utilidad de tuplas es inversamente proporcional al número de pulsaciones de teclas necesarias para declarar, empacar y desempacar ellos.

Para mí, es la costumbre, las manos hacia abajo: Las tuplas no resuelven cualquier problema nuevo para mí, sólo algunos ya puedo manejar bien. El intercambio de valores todavía se siente más fácil de la manera antigua - y, más importante, realmente no pensar en cómo cambiar "mejor". Es lo suficientemente bueno como está.

En lo personal, no creo que las tuplas son una gran solución para devolver varios valores -. Suena como un trabajo para struct s

Pero lo que si desea girar tres valores?

swap(a,b);
swap(b,c);  // I knew those permutation theory lectures would come in handy.

OK, así que con los valores 4, etc, finalmente, el n-tupla se vuelve menos código que n-1 permutas. Y con esta default swap hace 6 asignaciones en lugar de los 4 que tendría si se ha implementado una plantilla de tres ciclos a sí mismo, aunque yo espero que el compilador resolvería que para los tipos simples.

Puede llegar a escenarios en los swaps son difíciles de manejar o inapropiada, por ejemplo:

tie(a,b,c) = make_tuple(b*c,a*c,a*b);

es un poco incómodo para desempaquetar.

El punto es, formas, sin embargo, no se conocen de hacer frente a las situaciones más comunes que son buenas para las tuplas, y por lo tanto ninguna gran urgencia a tomar las tuplas. Por lo menos, yo no estoy seguro de que:

tie(a,b,c) = make_tuple(b,c,a);

no hace 6 copias, por lo que es completamente inadecuado para algunos tipos (colecciones siendo la más obvia). No dude en persuadirme de que las tuplas son una buena idea para los "grandes" tipos, al decir esto no es así: -)

Para devolver varios valores, tuplas son perfectos si los valores son de tipos incompatibles, pero algunas personas no les gusta si es posible que la persona que llama llegar ellos en el orden equivocado. Algunas personas no les gusta múltiples valores de retorno en absoluto, y no quieren fomentar su uso, haciendo que sean más fáciles. Algunas personas simplemente prefieren estructuras con nombres de parámetros de entrada y salida, y probablemente no podrían ser persuadidos con un bate de béisbol para usar tuplas. Sobre gustos no.

Como muchas personas señalaron, tuplas son simplemente no es tan útil como otras características.

  1. El intercambio y trucos giratorios son sólo trucos. Son totalmente confuso para aquellos que no los han visto antes, y ya que es casi todo el mundo, estos trucos son simplemente mala práctica de la ingeniería de software.

  2. devolver varios valores utilizando tuplas es mucho menos autodocumentado entonces las alternativas - volver tipos con nombre o el uso de referencias con nombre. Sin esta auto-documentado, es fácil confundir el orden de los valores devueltos, si son mutuamente convertibles, y no puede ser más sabio.

No todo el mundo puede impulsar el uso y TR1 aún no está ampliamente disponible.

Cuando se utiliza C ++ en sistemas embebidos, tirando en bibliotecas Boost obtiene compleja. Se acoplan entre sí, por lo que el tamaño de la biblioteca crece. Volverá estructuras de datos o bien utilizar el parámetro de paso en lugar de tuplas. Al devolver tuplas en Python es la estructura de datos en el orden y el tipo de los valores devueltos es simplemente no es explícita.

Rara vez se ve porque el código bien diseñado generalmente no necesita ellos- no hay muchos casos en la naturaleza, donde el uso de una estructura anónima es superior al uso de un nombrado uno. Puesto que toda una tupla representa realmente es una estructura anónima, en la mayoría de los codificadores en la mayoría de situaciones sólo tiene que ir con la cosa real.

Supongamos que tenemos una función "f", donde un retorno tupla podría tener sentido. Como regla general, dichas funciones son por lo general bastante complicadas que puedan fallar.

Si "f" puede fallar, se necesita un Regresar- estado después de todo, usted no quiere que las personas que llaman tienen que inspeccionar cada parámetro para detectar el fallo. "F" probablemente encaja en el patrón:

struct ReturnInts ( int y,z; }
bool f(int x, ReturnInts& vals);

int x = 0;
ReturnInts vals;
if(!f(x, vals)) {
    ..report error..
    ..error handling/return...
}

Eso no es bonito, pero a ver qué feo es la alternativa. Tenga en cuenta que todavía tengo un valor de estado, pero el código no es más fácil de leer y no es más corto. Es probable que sea más lento también, desde que incurrir en el costo de 1 copia de la tupla.

std::tuple<int, int, bool> f(int x);
int x = 0;
std::tuple<int, int, bool> result = f(x); // or "auto result = f(x)"
if(!result.get<2>()) {
    ... report error, error handling ...
}

Otra desventaja significativa se oculta en aquí- con "ReturnInts" Puedo añadir altera 's retorno al modificar 'ReturnInts' sin alterar 'f'' "f" s interfaz. La solución tupla no ofrece esa característica crítica, lo que hace que sea la respuesta inferior para cualquier código de la biblioteca.

Desde luego tuplas pueden ser útiles, pero como se mencionó que hay un poco de cabeza y un obstáculo o dos usted tiene que saltar a través de antes de poder siquiera realmente utilizarlos.

Si el programa encuentra constantemente los lugares donde se necesita para devolver múltiples valores o varios valores de canje, podría valer la pena para ir a la ruta tupla, pero por lo demás a veces es más fácil hacer las cosas de la manera clásica.

En términos generales, no todo el mundo ya se ha instalado Boost, y ciertamente no sería pasar por la molestia de descargar y configurar mi incluir directorios de trabajar con ella sólo por sus instalaciones de tupla. Creo que usted encontrará que las personas que ya utilizan Boost tienen más probabilidades de encontrar tupla utiliza en sus programas que los usuarios no-Boost y migrantes de otros idiomas (Python viene a la mente) son más propensos a ser simplemente molesto por la falta de tuplas en C ++ que explorar métodos de la adición de soporte tupla.

Como almacén de datos std::tuple tiene las peores características tanto de un struct y una matriz;todo el acceso se basa en la enésima posición, pero no se puede iterar a través de un tuple usando un for bucle.

Entonces, si los elementos del tuple son conceptualmente una matriz, usaré una matriz y si los elementos no son conceptualmente una matriz, una estructura (que tiene elementos con nombre) es más fácil de mantener.( a.lastname es más explicativo que std::get<1>(a)).

Esto deja la transformación mencionada por el OP como el único caso de uso viable para las tuplas.

Tengo la sensación de que muchos utilizan Boost.Any y Boost.Variant (con algo de ingeniería) en lugar de Boost.Tuple.

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