Domanda

ho visto questo grafico bello che classifica quale contenitore STL sarebbe adatto in base alle diverse esigenze di dati come:

- Dimensione fissa Vs dimensione variabile

- I dati dello stesso Tyme Vs tipo diverso

- Ordinati Vs dati non ordinati

- sequenziale Vs accesso casuale

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

Ho notato in quella immagine, che il C ++ STL non v'è alcun contenitore che è

  1. Formato variabile
  2. eterogenea (dati di tipo diverso).

Non C ++ avere qualcosa per questo?

PS -. Ci possono essere molti permutazioni fatte le diverse proprietà dei contenitori e molti altri ancora potrebbero non essere forniti in AWL

È stato utile?

Soluzione

Bene generalmente C ++ I contenitori sono stati progettati per gli oggetti in possesso di un solo tipo utilizzando i modelli. Se si desidera che i diversi tipi che sono tutti derivati ??da un tipo è possibile memorizzare un contenitore di puntatori (immagino si potrebbe anche avere un contenitore di * vuoto a qualsiasi cosa ...) ad esempio, std :: vector .

Se si desidera tipi completamente indipendenti, è possibile memorizzare gli oggetti che possono fare riferimento in modo sicuro questi altri tipi, come boost :: qualsiasi.

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

Alcuni esempi dal sito spinta:

#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 :: variante è simile, ma è necessario specificare tutti i tipi permessi, piuttosto che permettere qualsiasi tipo nel contenitore.

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

Altri suggerimenti

Il principio di base nella libreria standard è che "contenitori" sono omogenei; lo standard C ++ non prende in considerazione le cose come std::pair o std::tuple per essere dei contenitori. (Mi piacerebbe prendere in considerazione il grafico fuorviante, dal momento che li considera come contenitori.) Se avete bisogno di un contenitore eterogeneo, che avrebbe dovuto usare un contenitore di boost::variant, o qualcosa del genere.

std::pair e std::tuple sono difficilmente C ++ contenitori .... quindi no, non ci sono contenitori eterogenei nel STL, perché non è necessario averli built-in.

Ci sono diversi approcci per la creazione di tali contenitori. Gli approcci mi sento di raccomandare sono:

  • utilizzando il polimorfismo
  • utilizzando un tipo variante

Per polimorfismo, è possibile controllare Boost Pointer Container biblioteca.

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

imita i contenitori STL, ma fornisce funzionalità orientate verso polimorfismo:

  • elementi di Access come Base&
  • gestione della memoria automatica
  • comportamento specifico di copia (utilizzando metodi new_clone)
  • zucchero sintattico: dato boost::ptr_vector<Base>::iterator it;, *it è un Base&

Se i tipi sono estranei, l'altra possibilità è quella di utilizzare Boost Variante . Fondamentalmente, una variante è simile a:

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

Naturalmente, dal momento che di spinta, fornisce garanzie specifiche per assicurarsi che sia possibile accedere solo il membro del sindacato che è attualmente attivo e solleva la restrizione classi con costruttori / distruttori non essere utilizzabile in unioni tradizionali.

Fornisce inoltre servizi, come il static_visitor, che è l'equivalente di un interruttore del tipo, e farà l'errore di compilazione se uno dei possibili stati non viene visitato.

Una libreria che non è ancora accettato nel Boost. Ma che è stato proposto per l'inclusione si rivolge verso questo:

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

Si fornisce una classe bel nome any_collection che permette di avere un contenitore eterogeneo con boost :: :: type_erasure qualsiasi: http: // rawgit. com / joaquintides / poly_collection / sito web / doc / html / poly_collection / tutorial.html # poly_collection.tutorial.basics.boost_any_collection

In caso contrario, in C ++ 17 ci sono modo semplice per implementare questa: https://gieseanw.wordpress.com / 2017/05/03 / un-vero-eterogenea-contenitore-in-c /

Citando l'esempio suddetto articolo:

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

Poi utilizzabile facilmente:

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

L'autore afferma che è un'implementazione giocattolo, ma penso che questo è un modo molto intelligente per la sua attuazione, e ha un vantaggio semplicità sopra poly_collection o un vettore di varianti.

I contenitori eterogenei dimensione fissa (come std::tuple richiedono i tipi di essere conosciuti al momento della compilazione. Se si vuole fare una variabile di dimensioni contenitore eterogeneo, basta fare un std::vector<std::tuple<T1,T2,...,TN>>.

Se si desidera un contenitore eterogeneo dove i tipi non è noto al momento della compilazione (se che sarebbe variabile o fisso dimensioni) dovrete puntatori negozio (o puntatori intelligenti) per un tipo di base noto in fase di compilazione, o prendere in considerazione in alternativa, qualcosa di simile a un contenitore di boost::any. STL non fornisce direttamente un tale contenitore sia fisso o variabile dimensioni con elementi eterogenei determinate in fase di esecuzione.

Se l'elemento si memorizza sarebbe un boost::any o boost::variant allora si può indirettamente memorizzare i dati eterogenei.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top