una tuplas tupla tipos que datos conjuntos c++ tuples

tipos - tuplas en c++



¿Por qué el uso de tuplas en C++ no es más común? (12)

Al usar C ++ en sistemas integrados, extraer bibliotecas de Boost se vuelve complejo. Se juntan entre sí, por lo que el tamaño de la biblioteca crece. Devuelve estructuras de datos o usa el paso de parámetros en lugar de tuplas. Al devolver tuplas en Python, la estructura de datos está en el orden y tipo de los valores devueltos, simplemente no es explícita.

¿Por qué nadie parece usar las tuplas en C ++, ya sea Boost Tuple Library o la biblioteca estándar para TR1? He leído mucho código C ++, y muy pocas veces veo el uso de tuplas, pero a menudo veo muchos lugares donde las tuplas resolverían muchos problemas (generalmente devolviendo múltiples valores de las funciones).

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

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

Eso es ciertamente mejor que esto:

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

Por supuesto, siempre puedes hacer esto:

swap(a,b);

Pero, ¿y 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 variables múltiples de una función, que es probablemente un caso mucho más común que el intercambio de valores. El uso de referencias para devolver valores ciertamente no es muy elegante.

¿Hay grandes desventajas para las tuplas en las que no estoy pensando? Si no, ¿por qué raramente se usan? ¿Son más lentos? ¿O es simplemente que la gente no está acostumbrada a ellos? ¿Es una buena idea usar tuplas?


Ciertamente, las tuplas pueden ser útiles, pero como se mencionó, hay un poco de sobrecarga y un obstáculo o dos que tienes que pasar antes de que puedas usarlos realmente.

Si su programa encuentra constantemente lugares donde necesita devolver valores múltiples o intercambiar varios valores, puede valer la pena ir por la ruta de tupla, pero de lo contrario, a veces es más fácil hacer las cosas de la manera clásica.

En general, no todos ya tienen instalado Boost, y ciertamente no pasaría por la molestia de descargarlo y configurar mis directorios de inclusión para trabajar con él solo por sus instalaciones de tupla. Creo que encontrará que las personas que ya usan Boost tienen más probabilidades de encontrar usos de tupla en sus programas que los usuarios que no son de Boost, y los migrantes de otros idiomas (Python viene a la mente) es más probable que simplemente se molesten por la falta de tuplas en C ++ que explorar métodos para agregar compatibilidad con tuplas.


Como mucha gente señaló, las tuplas simplemente no son tan útiles como otras características.

  1. Los intercambios y los trucos giratorios son solo trucos. Son completamente confusos para aquellos que no los han visto antes, y ya que es casi todo el mundo, estos trucos son solo una mala práctica de ingeniería de software.

  2. La devolución de múltiples valores usando tuplas es mucho menos auto-documentable que las alternativas: devolver tipos nombrados o usar referencias nombradas. Sin esta auto-documentación, es fácil confundir el orden de los valores devueltos, si son mutuamente convertibles, y no ser más sabio.


Como una tienda de datos std::tuple tiene las peores características de una struct y una matriz; todo el acceso está basado en la posición número n, pero uno no puede iterar a través de una tuple usando un bucle for .

Entonces, si los elementos en la tuple son conceptualmente una matriz, usaré una matriz y si los elementos no son conceptualmente una matriz, una estructura (que tiene elementos nombrados) 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.


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

Considerar:

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

Así que si quieres hacer un uso extensivo de tuplas, obtienes tuple typedefs en todas partes o obtienes nombres de tipo molestos por todas partes. Me gustan las tuplas Los uso cuando sea necesario. Pero, por lo general, se limita a un par de situaciones, como un índice de elementos N o al usar multimaps para vincular los pares de iteradores de rango. Y generalmente es en un alcance muy limitado.

Es muy feo y hacky cuando se compara con algo como Haskell o Python. Cuando llegue C ++ 0x y obtengamos las palabras clave ''auto'', las tuplas comenzarán a verse mucho más atractivas.

La utilidad de las tuplas es inversamente proporcional al número de teclas necesarias para declarar, empaquetar y descomprimirlas.


No todos pueden usar boost, y TR1 todavía no está disponible.


Para mí, es un hábito, sin dudas: las tuplas no resuelven ningún problema nuevo para mí, solo unas pocas que ya puedo manejar bien. El intercambio de valores todavía se siente más fácil a la antigua usanza y, lo que es más importante, realmente no pienso en cómo intercambiar "mejor". Es lo suficientemente bueno como es.

Personalmente, no creo que las tuplas sean una gran solución para devolver múltiples valores; suena como un trabajo para struct s.


Porque aún no es estándar. Cualquier cosa no estándar tiene un obstáculo mucho más alto. Las piezas de Boost se han hecho populares porque los programadores las clamaban. (hash_map salta a la mente). Pero aunque la tupla es útil, no es una victoria tan abrumadora y clara que la gente se moleste con ella.


Raramente los ves porque el código bien diseñado generalmente no los necesita, no hay muchos casos en la naturaleza donde el uso de una estructura anónima sea superior al uso de uno con nombre. Dado que toda una tupla realmente representa es una estructura anónima, la mayoría de los codificadores en la mayoría de las situaciones solo se ajustan a lo real.

Digamos que tenemos una función "f" donde un retorno de tupla podría tener sentido. Como regla general, tales funciones son generalmente lo suficientemente complicadas como para que fallen.

Si "f" PUEDE fallar, necesita un estado de retorno; después de todo, no desea que las personas que llaman tengan que inspeccionar todos los parámetros para detectar fallas. "f" probablemente se ajusta al 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 mira lo fea que es la alternativa. Tenga en cuenta que todavía necesito un valor de estado, pero el código no es más legible y no más corto. Probablemente también sea más lento, ya que incurro en el costo de 1 copia con 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 ... }

Otro inconveniente importante está oculto aquí: con "ReturnInts" puedo agregar el retorno de alter f al modificar "ReturnInts" SIN ALTERAR la INTERFAZ "f". La solución de tupla no ofrece esa característica crítica, lo que la convierte en la respuesta inferior para cualquier código de biblioteca.


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


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

Como un ejemplo no mejorado: ¿Cuántas personas usan la funcionalidad que se encuentra en <algorithm> ?

En otras palabras, muchos programadores de C ++ son simplemente programadores de C que usan compiladores de C ++, y quizás std::vector y std::list . Esa es una razón por la cual el uso de boost::tuple no es más común.


Pero, ¿y si quieres rotar tres valores?

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

OK, entonces con 4 valores de etc., eventualmente la n-tupla se convierte en menos código que n-1 swaps. Y con el intercambio predeterminado esto hace 6 asignaciones en lugar de las 4 que tendría si implementara usted mismo una plantilla de tres ciclos, aunque espero que el compilador lo resuelva para los tipos simples.

Puede encontrar escenarios en los que los swaps son difíciles de manejar o inapropiados, por ejemplo:

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

es un poco incómodo de desempacar.

El punto es, sin embargo, que hay maneras conocidas de manejar las situaciones más comunes para las que las tuplas son buenas, y por lo tanto no es muy urgente tomar las tuplas. Si nada más, no estoy seguro de que:

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

no hace 6 copias, por lo que es totalmente inadecuado para algunos tipos (las colecciones son las más obvias). Siéntase libre de convencerme de que las tuplas son una buena idea para los tipos "grandes", al decir que esto no es así :-)

Para devolver valores múltiples, las tuplas son perfectas si los valores son de tipos incompatibles, pero a algunas personas no les gustan si es posible que la persona que llama los ingrese en el orden incorrecto. A algunas personas no les gustan los valores de retorno múltiples en absoluto, y no desean alentar su uso haciéndolos más fáciles. Algunas personas simplemente prefieren estructuras con nombre para los parámetros de entrada y salida, y probablemente no se las pueda persuadir con un bate de béisbol para que usen tuplas. Sin tener en cuenta el gusto.