vectores una tipos programacion plantillas matriz llenar ingresar ejemplos ejemplo datos como arreglos c++ templates stl iterator

una - vector de vectores c++



Inicializando un vector de tipo automático(desconocido) dentro de una función de plantilla en C++ (7)

Tengo una función de plantilla dentro de la cual quiero generar un vector que es de un tipo desconocido. Traté de hacerlo automático, pero el compilador dice que no está permitido.

La función de plantilla obtiene iteradores o punteros como se ve en el programa de prueba dentro de la función principal seguida. ¿Cómo se puede solucionar el problema?

template<class Iter> auto my_func(Iter beg, Iter end) { if (beg == end) throw domain_error("empty vector"); auto size = distance(beg, end); vector<auto> temp(size); // <--HERE COMPILER SAYS CANNOT BE AUTO TYPE copy(beg, end, temp->begin); . . return .... } int main() { int bips[] = {3, 7, 0, 60, 17}; // Passing pointers of array auto g = my_func(bips, bips + sizeof(bips) / sizeof(*bips)); vector<int> v = {10, 5, 4, 14}; // Passing iterators of a vector auto h = my_func(v.begin(), v.end()); return 0; }


Es posible que esté buscando algo así como

std::vector<typename std::remove_reference<decltype(*beg)>::type> temp(beg, end);

Manifestación


La razón por la que el auto no funciona es porque no está permitido en ese contexto. No puede proporcionar auto en lugar de un argumento de plantilla. El curso de acción correcto cuando se quiere que el compilador deduzca automáticamente un argumento de plantilla es no proporcionar ningún argumento. Sin embargo, en este caso, no hay forma de que el compilador deduzca qué tipo debería ser. Debe proporcionar el tipo explícitamente.

Hay muchas maneras de averiguar cuál es el tipo correcto para su vector. Puede usar std::iterator_traits para obtener información sobre un iterador, incluido el tipo de valor al que se refiere. Utilizaría typename std::iterator_traits<Iter>::value_type .

#include <algorithm> #include <iterator> #include <stdexcept> #include <vector> template<class Iter> auto my_func(Iter beg, Iter end) { if (beg == end) throw std::domain_error("empty vector"); auto size = std::distance(beg, end); using t_value = typename std::iterator_traits<Iter>::value_type; std::vector<t_value> temp(size); std::copy(beg, end, temp.begin()); return temp; } int main() { int bips[] = { 3,7,0,60,17 };//Passing pointers of array auto g = my_func(bips, bips + sizeof(bips) / sizeof(*bips)); std::vector<int> v = { 10,5,4,14 };//Passing iterators of a vector auto h = my_func(v.begin(), v.end()); return 0; }

Me gustaría señalar que no hay motivo para verificar 0 rangos de tamaño. Devolvería correctamente un vector vacío.

También puede simplificar un poco el cuerpo de my_func aprovechando el hecho de que std::vector tiene un constructor que acepta un par de iteradores y copia ese rango.

template<class Iter> auto my_func(Iter beg, Iter end) { using t_value =typename std::iterator_traits<Iter>::value_type; return std::vector<t_value>(beg, end); }


No es cierto que el tipo no se conoce. El tipo de vector que desea crear es del mismo tipo de Iter .

Simplemente obtenga el tipo subyacente ya sea usando decltype o usando el rasgo de tipo de iterador de la siguiente manera:

  • decltype -> std::vector<typename remove_reference<decltype(*beg)>::type> temp(beg, end);

  • iterator type trait

como sigue

using Type = std::iterator_traits<Iter>::value_type; std::vector<Type>...


No puedes usar un std::vector de auto . Puede usar std :: iterator_traits en su lugar:

std::vector<typename std::iterator_traits<Iter>::value_type> temp(size);


Puede extraer información de tipo de puntero / iterator usando iterator_traits . value_type es el rasgo específico que le interesa, por lo que puede hacer:

const vector<typename iterator_traits<Iter>::value_type> temp(beg, end);

Ejemplo en vivo


Resolvería esto de forma ligeramente diferente de lo que su pregunta parece estar pidiendo.

Primero, considero que los rangos son un mejor tipo fundamental que tomar dos iteradores. Los dos iteradores están acoplados, deberían ser un argumento. Un rango es una estructura simple de dos iteradores, con algunos métodos de utilidad:

template<class It> struct range_t: std::iterator_traits<It> { It b{}, e{}; It begin() const { return b; } It end() const { return e; } bool empty() const { return begin()==end(); } auto size() const { return std::distance(begin(), end()); } // etc range_t()=default; range_t(range_t const&)=default; range_t(range_t &&)=default; range_t& operator=(range_t const&)=default; range_t& operator=(range_t &&)=default; }; template<class It> range_t<It> make_range( It s, It f ) { return {std::move(s), std::move(f)}; }

range_t s range_t correctamente el iterador de inicio y final.

Ahora

template<class Range> auto my_func(Range&& range) { // todo } template<class Iter> auto my_func(Iter beg, Iter end) { return my_func(make_range(std::move(beg), std::move(end))); }

es el primer paso. O simplemente elimine por completo la versión de dos iteradores y espere que la persona que llama empaque sus iteradores por usted.

template<class Range> auto my_func(Range&& range) { if (range.empty()) throw domain_error("empty vector"); // todo }

Ok, ahora quieres hacer esto:

auto size = range.size(); vector<auto> temp(size);//<--HERE COMPILER SAYS CANNOT BE AUTO TYPE copy(range.begin(), range.end(), temp->begin);

pero esa es una operación común. Entonces lo escribimos para rango:

template<class Range> auto as_vector( Range const& r ) { using value_type = typename Range::value_type; std::vector<value_type> v( range.begin(), range.end() ); return v; }

dándonos:

template<class Range> auto my_func(Range&& range) { if (range.empty()) throw domain_error("empty vector"); auto v = as_vector(range); // ... return ...; }

Hemos descompuesto su problema en primitivas simples que tienen significado y hemos trasladado la complejidad de la implementación a esas primitivas. La "lógica de negocios" de su my_func ya no le importa qué pasos tome para convertir un rango en un vector.

Esto hace que my_func más legible, siempre y cuando tengas la confianza de que as_vector(range) realmente devuelve ese rango como un vector.


Si tiene un compilador compatible con C ++ 17, puede beneficiarse de la deducción de argumentos de plantilla de clase .

Entonces, a menos que tenga una razón específica para llenar su vector con std::copy , podría escribir su código así:

template<class Iter> auto my_func(Iter beg, Iter end) { if (beg == end) throw domain_error("empty vector"); vector temp(beg, end); // do the remaining stuff return .... }

Si esta característica no está disponible en tu compilador, votaría por

vector<typename iterator_traits<Iter>::value_type> temp(beg, end);

como en la respuesta de Jonathan