2008-11-16 12 views
48

¿Hay una buena manera en C++ para implementar (o falsificar) un tipo para un vector genérico de vectores?Vector genérico de vectores en C++

Ignore la cuestión de cuándo un vector de vectores es una buena idea (a menos que haya algo equivalente que siempre es mejor). Supongamos que modela con precisión el problema y que una matriz no modela el problema con precisión. Supongamos también que las funciones con plantilla que toman estas cosas como parámetros necesitan manipular la estructura (por ejemplo, llamar a push_back), por lo que no pueden simplemente tomar un tipo genérico compatible con [][].

Lo que quiero hacer es:

template<typename T> 
typedef vector< vector<T> > vecvec; 

vecvec<int> intSequences; 
vecvec<string> stringSequences; 

pero por supuesto eso no es posible, ya que no se puede typedef plantilla.

#define vecvec(T) vector< vector<T> > 

está cerca, y ahorraría duplicar el tipo a través de cada función con plantilla que opera en vecvecs, pero no sería popular con la mayoría de los programadores de C++.

Respuesta

51

Desea tener los tipos de plantilladef. Eso es no pero compatible con el C++ actual. Una solución consiste en hacer

template<typename T> 
struct vecvec { 
    typedef std::vector< std::vector<T> > type; 
}; 

int main() { 
    vecvec<int>::type intSequences; 
    vecvec<std::string>::type stringSequences; 
} 

En el próximo C++ (llamado C++ 0x, 1x C++ debido al 2010), esto sería posible:

template<typename T> 
using vecvec = std::vector< std::vector<T> >; 
+13

Creo que también han solucionado la necesidad de espacios en >> –

+0

de hecho, tienen :) –

4

puede simplemente crear una nueva plantilla:

#include <string> 
#include <vector> 

template<typename T> 
struct vecvec : public std::vector< std::vector<T> > {}; 

int main() 
{ 
    vecvec<int> intSequences; 
    vecvec<std::string> stringSequences; 
} 

Si lo que usted tiene que recordar que el destructor de vector es que no son virtuales y no a hacer algo como esto:

void test() 
{ 
    std::vector< std::vector<int> >* pvv = new vecvec<int>; 
    delete pvv; 
} 
+4

Te encontrarás con perder todos los prácticos constructores del vector . Debe definirlos, simplemente pasando los argumentos al padre. Una posibilidad, pero no una solución pobre y mala. – xtofl

+0

-1 La respuesta en sí está bien compuesta y señala uno de los principales defectos de la solución presentada. Sin embargo, este defecto y otros son suficientes para un voto negativo, creo. –

5

Uso Boost.MultiArray que se implementa en la biblioteca de impulso.

HTH

+0

+1 por mencionar esta biblioteca – mloskot

2

Puede implementar tipo básico vectores de vector usando std::vector como base:

#include <iostream> 
#include <ostream> 
#include <vector> 
using namespace std; 

template <typename T> 
struct vecvec 
{ 
    typedef vector<T> value_type; 
    typedef vector<value_type> type; 
    typedef typename type::size_type size_type; 
    typedef typename type::reference reference; 
    typedef typename type::const_reference const_reference; 

    vecvec(size_type first, size_type second) 
     : v_(first, value_type(second, T())) 
    {} 

    reference operator[](size_type n) 
    { return v_[n]; } 

    const_reference operator[](size_type n) const 
    { return v_[n]; } 

    size_type first_size() const 
    { return v_.size(); } 

    size_type second_size() const 
    { return v_.empty() ? 0 : v_[0].size(); } 

    // TODO: replicate std::vector interface if needed, like 
    //iterator begin(); 
    //iterator end(); 

private: 
    type v_; 

}; 

// for convenient printing only 
template <typename T> 
ostream& operator<<(ostream& os, vecvec<T> const& v) 
{ 
    typedef vecvec<T> v_t; 
    typedef typename v_t::value_type vv_t; 
    for (typename v_t::size_type i = 0; i < v.first_size(); ++i) 
    { 
     for (typename vv_t::size_type j = 0; j < v.second_size(); ++j) 
     { 
      os << v[i][j] << '\t'; 
     } 
     os << endl; 
    } 
    return os; 
} 

int main() 
{ 
    vecvec<int> v(2, 3); 
    cout << v.first_size() << " x " << v.second_size() << endl; 
    cout << v << endl; 

    v[0][0] = 1; v[0][1] = 3; v[0][2] = 5; 
    v[1][0] = 2; v[1][1] = 4; v[1][2] = 6; 
    cout << v << endl; 
} 

Es sólo un contenedor muy simple que imita una matriz (siempre y cuando las promesas de usuario, por mejorando la definición de vecvec o por el uso apropiado, forma rectangular).

+0

Desafortunadamente, una matriz no modela el problema. Los datos no son "rectangulares", las filas diferentes son de diferentes longitudes. –

+0

@Steve Jessop: en general, al trabajar con el vector de vectores, sí hay tal eventualidad debido a la exposición de push_back, etc., pero se supone que es una ilustración, una solución primitiva y dejo mejoras al lector, es decir, para garantizar el tamaño para las filas se mantiene, no para exponer las operaciones que podrían modificar la dimensión del vector de fila, etc. – mloskot

Cuestiones relacionadas