Pregunta

Vi este bonito gráfico que clasifica qué contenedor STL se adaptaría en función de diferentes requisitos de datos como:

- Tamaño fijo frente a tamaño variable

- Datos del mismo tipo tyme vs diferente

- Datos ordenados vs sin clasificar

- Acceso aleatorio secuencial vs

http://plasmahh.projectiwear.org/cce_clean.svg

Noto en esa imagen, que C ++ stl no hay contenedor que sea

  1. Tamaño variable
  2. Heterogéneo (datos de diferentes tipos).

¿No tiene C ++ algo para esto?

PD: puede haber muchas permutaciones hechas de las diferentes propiedades de los contenedores y muchas otras también podrían no proporcionarse en STL.

¿Fue útil?

Solución

Bueno, generalmente los contenedores C ++ están diseñados para mantener objetos de un solo tipo usando plantillas. Si desea diferentes tipos que se derivan de un tipo, puede almacenar un contenedor de punteros (supongo que también podría tener un contenedor de vacío* a cualquier cosa ...) por ejemplo, std :: vectoru003CMyBaseType*> .

Si desea tipos completamente no relacionados, puede almacenar objetos que puedan hacer referencia de forma segura a esos otros tipos, como Boost :: Any.

http://www.boost.org/doc/libs/1_47_0/doc/html/any.html

Algunos ejemplos del sitio de Boost:

#include <list>
#include <boost/any.hpp>

using boost::any_cast;
typedef std::list<boost::any> many;

void append_int(many & values, int value)
{
    boost::any to_append = value;
    values.push_back(to_append);
}

void append_string(many & values, const std::string & value)
{
    values.push_back(value);
}

bool is_int(const boost::any & operand)
{
    return operand.type() == typeid(int);
}
bool is_char_ptr(const boost::any & operand)
{
    try
    {
        any_cast<const char *>(operand);
        return true;
    }
    catch(const boost::bad_any_cast &)
    {
        return false;
    }
}

Boost :: La variante es similar, pero usted especifica todos los tipos permitidos, en lugar de permitir cualquier tipo en su contenedor.

http://www.boost.org/doc/libs/1_47_0/doc/html/variant.html

std::vector< boost::variant<unsigned, std::string> > vec;
vec.push_back( 44);
vec.push_back( "str" );
vec.push_back( SomthingElse(55, 65) ); //not allowed

Otros consejos

El principio básico en la biblioteca estándar es que los "contenedores" son homogéneos; El estándar C ++ no considera cosas como std::pair o std::tuple ser contenedores. (Consideraría el gráfico engañoso, ya que los considera como contenedores). Si necesita un contenedor heterogéneo, tendría que usar un contenedor de boost::variant, O algo por el estilo.

std::pair y std::tuple no son contenedores C ++ ... así que no, no hay contenedores heterogéneos en el STL, porque no es necesario tenerlos incorporados.

Hay varios enfoques para crear tales contenedores. Los enfoques que recomendaría son:

  • usando polimorfismo
  • Usando un tipo de variante

Para el polimorfismo, puedes verificar Boost Pointer Container biblioteca.

boost::ptr_vector<Base> vec;
vec.push_back(new Derived);
vec.push_back(new Derived2);

Imita los contenedores STL, pero proporciona funcionalidades orientadas al polimorfismo:

  • Accesar elementos como Base&
  • Manejo automático de memoria
  • Comportamiento de copia específica (usando new_clone métodos)
  • Azúcar sintáctico: dado boost::ptr_vector<Base>::iterator it;, *it es un Base&

Si sus tipos no están relacionados, la otra posibilidad es usar Variante de refuerzo. Básicamente, una variante es similar a:

enum { Type1, Type2, ... } _type;
union {
  SomeType1 _1;
  SomeType2 _2;
  ...
} _u;

Por supuesto, dado que es impulso, proporciona garantías específicas para asegurarse de que solo puede acceder al miembro de la unión que actualmente está activo y eleva la restricción en clases con constructores / destructores que no se pueden usar en los sindicatos tradicionales.

También proporciona instalaciones, como la static_visitor, que es el equivalente de un interruptor en el tipo, y hará el error de compilación si no se visita uno de los estados posibles.

Una biblioteca que aún no se acepta en Boost. Pero que se propuso para su inclusión está dirigido a esto:

http://rawgit.com/joaquintides/poly_collection/website/doc/html/index.html

Proporciona una buena clase llamada Any_Collection que permite tener un contenedor heterogéneo a través de Boost :: Type_erasure :: Any: Any:http://rawgit.com/joaquintides/poly_collection/website/doc/html/poly_collection/tutorial.html#poly_collection.tutorial.basics.boost_any_collection

De lo contrario, en C ++ 17 hay una forma simple de implementar esto:https://gieseanw.wordpress.com/2017/05/03/a-true-heterogeneus-container-in-c/

Citando el ejemplo del artículo antes mencionado:

namespace andyg{
struct heterogeneous_container{
private:
    template<class T>
    static std::unordered_map<const heterogeneous_container*, std::vector<T>> items;
public:
    template <class T>
    void push_back(const T& _t)
    {
        items<T>[this].push_back(_t);
    }
};

// storage for our static members
template<class T>
std::unordered_map<const heterogeneous_container*, std::vector<T>> heterogeneous_container::items;
} // andyg namespace

Luego utilizable fácilmente:

andyg::heterogeneous_container c;
c.push_back(1);
c.push_back(2.f);
c.push_back('c');
struct LocalStruct{};
c.push_back(LocalStruct{});

El autor afirma que es una implementación de juguetes, pero creo que esta es una forma realmente inteligente de implementarla, y tiene una ventaja de simplicidad sobre Poly_Collection o un vector de variantes.

Los contenedores heterogéneos de tamaño fijo (como std::tuple requiere que los tipos se conozcan en el momento de la compilación. Si desea hacer un contenedor heterogéneo de tamaño variable, simplemente haga un std::vector<std::tuple<T1,T2,...,TN>>.

Si desea un contenedor heterogéneo donde los tipos no se conocen en el momento de la compilación (ya sea que sea variable o de tamaño fijo) tendrá que almacenar punteros (o punteros inteligentes) a un tipo base conocido en el momento de la compilación, o alternativamente considerar algo como un contenedor de boost::any. El STL no proporciona directamente dicho contenedor en el tamaño fijo o variable con elementos heterogéneos determinados en el tiempo de ejecución.

Si el elemento que almacena sería un boost::any o boost::variant Luego puede almacenar indirectamente datos heterogéneos.

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