¿Existe una forma elegante de crear e inicializar un me const std::vector<const T>
gusta const T a[] = { ... }
para un número fijo (y pequeño) de valores?
Necesito llamar a una función con frecuencia que espera una vector<T>
, pero estos valores nunca cambiarán en mi caso.
En principio pensé en algo como
namespace {
const std::vector<const T> v(??);
}
ya que v no se utilizará fuera de esta unidad de compilación.
Si está preguntando cómo inicializar un vector constante para que tenga contenidos interesantes, entonces la respuesta probablemente sea usar el constructor de copia. Primero, llena laboriosamente un vector, luego crea su nuevo vector constante a partir de él. O puede usar el
vector<InputIterator>(InputIterator, InputIterator)
plantilla constructor para inicializar desde algún otro tipo de contenedor o matriz. Si es una matriz, entonces podría haberse definido con una lista de inicialización.Es de esperar que algo como esto se acerque a lo que desea:
const T ra[3] = {t1, t2, t3}; const vector<const T> v(ra, ra+3);
Si está preguntando cómo pasar un vector constante a una función que toma un vector, la respuesta es:
o
const_cast
para eliminar la constness con el fin de pasarla a una función que toma un vector no constante pero que usted sabe que no modificará el vector.Esto último es una de esas cosas que, con toda razón, hará que cualquiera que lo vea haga comentarios sobre las gafas y el hecho de que no hacen nada. Para eso
const_cast
es exactamente , pero hay un argumento razonablemente fuerte que dice que si lo necesitaconst_cast
, ya ha perdido.Hacer ambas cosas (crear un vector constante a partir de uno que no sea constante con el constructor de copia y luego desechar la constante) es definitivamente incorrecto; debería haber usado un vector no constante. Así que elige como máximo uno de estos para hacer ...
[ Editar: acabo de notar que estás hablando de una diferencia entre
vector<T>
yconst vector<const T>
. Desafortunadamente en el STL,vector<const T>
yvector<T>
son tipos completamente no relacionados, y la única forma de convertir entre ellos es copiando. Esta es una diferencia entre vectores y matrices: aT**
se puede convertir de forma silenciosa y segura aconst T *const *
]fuente
Camino corto y sucio (similar al de Boost
list_of()
)#include <iostream> #include <vector> #include <iterator> #include <algorithm> using namespace std; template <typename T> struct vlist_of : public vector<T> { vlist_of(const T& t) { (*this)(t); } vlist_of& operator()(const T& t) { this->push_back(t); return *this; } }; int main() { const vector<int> v = vlist_of<int>(1)(2)(3)(4)(5); copy(v.begin(), v.end(), ostream_iterator<int>(cout, "\n")); }
Ahora, C ++ 11 tiene listas de inicializadores, por lo que no es necesario que lo haga de esa manera ni siquiera use Boost. Pero, como ejemplo, puede hacer lo anterior en C ++ 11 de manera más eficiente de esta manera:
#include <iostream> #include <vector> #include <utility> #include <ostream> using namespace std; template <typename T> struct vlist_of : public vector<T> { vlist_of(T&& t) { (*this)(move(t)); } vlist_of& operator()(T&& t) { this->push_back(move(t)); return *this; } }; int main() { const vector<int> v = vlist_of<int>(1)(2)(3)(4)(5); for (const auto& i: v) { cout << i << endl; } }
Pero todavía no es tan eficiente como usar una lista de inicializadores de C ++ 11 porque no hay
operator=(vlist_of&&)
un vector definido.La forma de tjohns20 modificada como la siguiente podría ser un mejor c ++ 11
vlist_of
:#include <iostream> #include <vector> #include <utility> using namespace std; template <typename T> class vlist_of { public: vlist_of(T&& r) { (*this)(move(r)); } vlist_of& operator()(T&& r) { v.push_back(move(r)); return *this; } vector<T>&& operator()() { return move(v); } private: vector<T> v; }; int main() { const auto v = vlist_of<int>(1)(2)(3)(4)(5)(); for (const auto& i : v) { cout << i << endl; } }
fuente
Como han dicho otros, no puede iniciar un vector de la misma manera que puede iniciar una matriz de estilo C, a menos que le dé punteros a una matriz de origen. Pero en ese caso, si su vector es una constante global, ¿por qué no usar una antigua matriz de estilo C?
const int MyInts[] = { 1, 2, 3, 4, 5}; const size_t NumMyInts = sizeof(MyInts)/sizeof(MyInts[0]);
Incluso puede usar algoritmos STL contra esta matriz, de la misma manera que usaría algoritmos contra un vector constante ...
const int* myInt = std::find( &MyInts[0], &MyInts[NumMyInts], 3);
fuente
Puedes hacerlo en dos pasos:
namespace { const T s_actual_array[] = { ... }; const std::vector<const T> s_blah(s_actual_array, s_actual_array + (sizeof(s_actual_array) / sizeof(s_actual_array[0]))); }
Quizás no sea tan hermoso como le gustaría, pero funcional.
fuente
Qué tal si:
int ar[]={1,2,3,4,5,6}; const int TotalItems = sizeof(ar)/sizeof(ar[0]); std::vector<int> v(ar, ar+TotalItems);
fuente
Antigua pregunta, pero me encontré con el mismo problema hoy, este es el enfoque que fue más aceptable para mis propósitos:
vector<int> initVector(void) { vector<int> initializer; initializer.push_back(10); initializer.push_back(13); initializer.push_back(3); return intializer; } int main() { const vector<int> a = initVector(); return 0; }
Ejemplo para evitar copias excesivas:
vector<int> & initVector(void) { static vector<int> initializer; if(initializer.empty()) { initializer.push_back(10); initializer.push_back(13); initializer.push_back(3); } return intializer; } int main() { const vector<int> & a = initVector(); return 0; }
fuente
Si son todos iguales, puedes hacerlo
vector<T> vec(num_items, item);
pero supongo que no lo son, en cuyo caso la forma más ordenada es probablemente:
vector<T> vec(num_items); vec[0] = 15; vec[1] = 5; ...
C ++ 0x le permitirá usar una lista de inicializadores exactamente de la forma en que está pensando, pero eso no es muy bueno en este momento, desafortunadamente.
fuente
Según la respuesta de Shadow2531, estoy usando esta clase para inicializar vectores, sin heredar realmente de std :: vector como lo hizo la solución de Shadow
template <typename T> class vector_init { public: vector_init(const T& val) { vec.push_back(val); } inline vector_init& operator()(T val) { vec.push_back(val); return *this; } inline std::vector<T> end() { return vec; } private: std::vector<T> vec; };
Uso:
std::vector<int> testVec = vector_init<int>(1)(2)(3)(4)(5).end();
En comparación con la solución de Steve Jessop, crea mucho más código, pero si la creación de la matriz no es crítica para el rendimiento, me parece una buena forma de inicializar una matriz en una sola línea.
fuente
No estoy seguro de si te entendí bien. Entiendo su pregunta de esta manera: desea inicializar un vector en una gran cantidad de elementos. ¿Qué tiene de malo usar
push_back()
en el vector? :-)Si conoce la cantidad de elementos a almacenar (o está seguro de que almacenará menos que la próxima potencia de 2) puede hacer esto, si tiene un vector de punteros de tipo X (funciona solo con punteros):
std::vector< X* > v; v.reserve(num_elems); X* p = v.begin(); for (int count = 0; count < num_elems; count++) p[count] = some_source[count];
Tenga cuidado de agregar más de la siguiente potencia de 2 elementos, incluso si se usa
push_back()
.v.begin()
Entonces, los punteros a no serán válidos.fuente