2

Estoy empezando a familiarizarme un poco con los stl y mi problema es el siguiente. En todos los tutos te dicen las funciones, como agregar elementos y mostrarlos, recorrerlos, etc. Yo tengo esta estructura:

struct Libro{
string nombre;
int codigo;
bool disp;
};

y esta lista list <Libro> libro

Con esta función agrego libros a la lista:

Libro insertarlibro(){
    string nombre;
    int codigo;
    bool disp=true;
    cout<<"\nIngrese el nombre del libro: ";
    getline(cin,nombre);
    cout<<"\nIngrese el codigo: ";
    cin>>codigo;
    return{nombre,codigo,disp};
}

desde el main

libro.push_back(insertarlibro())

y se supone que con esta función se muestran los libros:

void mostrarlibros( list<Libro> & sList )
{
    list<Libro>::iterator pos;
    pos = sList.begin();
    while( pos != sList.end())
    {
        cout<<*pos<<endl;
        pos++;
     }
}

Pero obviamente, si la estructura que tengo consta de tres datos nombre, código y disponibilidad, *pos no va a mostrar los 3, entonces yo quiero saber que debe colocar en el cout<< para poder mostrar el nombre, código y disp de cada libro agregado. He buscado bastante y no consigo una guía de como mostrar los elementos de una estructura agregado en un contenedor en este caso el list

Federico Madoery
  • 2,858
  • 9
  • 19
Marcel Salazar
  • 137
  • 1
  • 1
  • 11

1 Answers1

2

Esa función confía en que el dato pasado a std::cout tenga sobrecargado el operador de inyección de datos (operator <<).

Es muy fácil de sobrecargar dicho operador:

std::ostream &operator<<(std::ostream &o, const Libro &l)
{
    return o << l.nombre << ' ' << l.codigo << ' ' << l.disp;
}

El flujo de datos es un flujo de salida genérico (std::ostream) por lo que vas a poder enviar datos de tipo Libro a cualquier flujo de salida (std::cout o un archivo, por ejemplo).

Otras cosas a tener en cuenta.

Tu función de muestra de libros es semánticamente incorrecta; dado que pretendes mostrar los datos de un contenedor, se asume que no tienes intención de modificar dicho contenedor, así pues el parámetro debería ser constante:

void mostrarlibros( const list<Libro> & sList )
//                  ~~~~~ <--- La lista es de solo lectura

Por otro lado, los bucles for y while son fácilmente intercambiables, así que sería indiferente el uso de uno u otro; pero en general se sigue una guía para saber cuál escoger:

  • Si se sabe cuántas iteraciones serán necesarias: se usa el bucle for.
  • Si no se sabe las iteraciones que serán necesarias: se usa el bucle while.

En tu caso, lo que cabría esperar es un bucle for:

void mostrarlibros( const list<Libro> & sList )
//                  ~~~~~ <--- La lista es de solo lectura
{
    for (auto b = sList.begin(), e = sList.end(); b != e; ++b)
//                      ~~~~~              ~~~
//  iteramos tantas veces como elementos existan entre begin y end
    {
        cout<<*b<<endl;
    }
}

Pero este tipo de bucles son farragosos e incómodos, lo habitual cuando se recorren colecciones de datos es usar el bucle for de rango:

void mostrarlibros( const list<Libro> & sList )
//                  ~~~~~ <--- La lista es de solo lectura
{
    for (const auto &libro : sList)
//                   ~~~~~~~~~~~~~ <--- por cada Libro en sList...
    {
        cout<<libro<<'\n';
    }
}

He substituido el std::endl por '\n' ya que suele ser mejor idea, consulta este hilo para saber por qué.

PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82
  • Cuando lei tu respuesta quede tipo poker face.. no sabia que hacer con eso.. pero copie y pegue eso arriba de la funcion mostrar y mostro los libros en el contenedor.. que genial.. ese termino lo habia escuchado antes "sobrecarga de operadores" estoy buscando informacion sobre eso para saber mejor como funciona lo que me estas colocando.. otro cosa: en caso de que quiera buscar entre los codigos registrados y me muestre un libro en especifico? – Marcel Salazar Jul 30 '18 at 14:25
  • 1
    Para buscar dentro de un contenedor un dato que cumpla con una condición determinada, lo más adecuado es usar la función [`std::find_if`](https://en.cppreference.com/w/cpp/algorithm/find) de la librería de algoritmos. Te invito a hacer una pregunta adicional si quieres más detalles. – PaperBirdMaster Jul 30 '18 at 14:29
  • con el ultimo codigo que me pasastes me salta este error `[Error] range-based 'for' loops are not allowed in C++98 mode` otra cosa, la unica forma de mostrar cada libr es sobrecargando el operador de salida? no hay otra forma? es que todabia no me familiarizo con las sobrecargas – Marcel Salazar Jul 30 '18 at 22:27
  • 1
    @MarcelSalazar debes habilitar C++11 en tu proceso de compilación, por ello te arroja ese error –  Jul 31 '18 at 02:48
  • 1
    El error que recibes es claro y conciso, tal vez no lo entiendes por estar en inglés, te lo traduzco: *el bucle 'for' de rango no está permitido en el modo C++98*. Viene a decir que el compilador está usando el estándar C++98 y en dicho estándar el bucle `for` de rango aún no existía; necesitas como mínimo compilar con el estándar C++11. Cada compilador define el estándar con el que compilar de manera diferente pero en general basta con añadir `std=C++11` a los parámetros de compilación. – PaperBirdMaster Jul 31 '18 at 06:21
  • La única forma de mostrar un libro pasándolo a un flujo de salida de datos (como `std::cout`) es sobrecargando el operador de inyección de datos (`operator < – PaperBirdMaster Jul 31 '18 at 06:22