c++ unions boost-variant boost-any

c++ - ¿Cómo impulsar:: variante y aumentar:: cualquier trabajo?



unions boost-variant (3)

¿Cómo funcionan internamente la variante y cualquiera de la biblioteca de impulso? En un proyecto en el que estoy trabajando, actualmente uso una unión etiquetada. Quiero usar algo más, porque los sindicatos en C ++ no te permiten usar objetos con constructores, destructores u operadores de asignación sobrecargados.

Consulté el tamaño de cualquiera y variante, e hice algunos experimentos con ellos. En mi plataforma, la variante toma el tamaño de su tipo más largo posible más 8 bytes: creo que es solo 8 bytes o tipo de información y el resto es el valor almacenado. Por otro lado, cualquiera solo toma 8 bytes. Como estoy en una plataforma de 64 bits, creo que cualquiera solo tiene un puntero.

¿Cómo sabe alguien qué tipo tiene? ¿Cómo logra Variant lo que hace a través de las plantillas? Me gustaría saber más sobre estas clases antes de usarlas.


La diferencia clave entre boost::any y boost::variant es que any puede almacenar cualquier tipo, mientras que la variant puede almacenar solo uno de un conjunto de tipos enumerados. any tipo almacena un puntero void* para el objeto, así como un objeto typeinfo para recordar el tipo subyacente y aplicar algún grado de seguridad de tipo. En boost::variant , calcula el objeto de tamaño máximo y utiliza "ubicación nueva" para asignar el objeto dentro de este búfer. También almacena el tipo o el índice de tipo.

Tenga en cuenta que si tiene instalado Boost, debería poder ver los archivos fuente en "any.hpp" y "variant.hpp". Simplemente busque "include / boost / variant.hpp" e "include / boost / any.hpp" en "/ usr", "/ usr / local" y "/ opt / local" hasta que encuentre los encabezados instalados, y puedes echar un vistazo.

Editar
Como se ha señalado en los comentarios a continuación, hubo una ligera inexactitud en mi descripción de boost :: any. Si bien se puede implementar utilizando void* (y una devolución de llamada con destrucción de plantilla para eliminar correctamente el puntero), la implementación real usa any<T>::placeholder* , con any<T>::holder<T> como subclases de any<T>::placeholder para unificar el tipo.


Si lees el boost :: cualquier documentación, proporcionan la fuente de la idea: http://www.two-sdg.demon.co.uk/curbralan/papers/ValuedConversions.pdf

Es información básica escondida, una habilidad esencial de C ++ para tener. ¡Aprenderlo!

Dado que la respuesta más votada aquí es totalmente incorrecta, y tengo mis dudas de que la gente vaya a ver la fuente para verificar ese hecho, aquí hay una implementación básica de una interfaz similar que ajustará cualquier tipo con una función f () y permite que se llame:

struct f_any { f_any() : ptr() {} ~f_any() { delete ptr; } bool valid() const { return ptr != 0; } void f() { assert(ptr); ptr->f(); } struct placeholder { virtual ~placeholder() {} virtual void f() const = 0; }; template < typename T > struct impl : placeholder { impl(T const& t) : val(t) {} void f() const { val.f(); } T val; }; // ptr can now point to the entire family of // struct types generated from impl<T> placeholder * ptr; template < typename T > f_any(T const& t) : ptr(new impl<T>(t)) {} // assignment, etc... };

boost :: any hace lo mismo básico excepto que f () realmente devuelve typeinfo const& y proporciona otro acceso de información a la función any_cast para que funcione.


boost::any just snapshots the typeinfo while the constructor de plantilla se ejecuta: tiene un puntero a una clase base no-templada que proporciona acceso a typeinfo, y el constructor derivó una clase específica de tipo que satisface esa interfaz. La misma técnica puede usarse para capturar otras capacidades comunes de un conjunto de tipos (por ejemplo, transmisión, operadores comunes, funciones específicas), aunque el impulso no ofrece control de esto.

boost :: variant es conceptualmente similar a lo que has hecho anteriormente, pero al no usar literalmente una union y tomar un enfoque manual para la construcción / destrucción de objetos en su buffer (mientras se manejan los problemas de alineación explícitamente) funciona alrededor de las restricciones que C ++ tiene tipos complejos en union reales.