Desde que UncleBen trajo su LineInputIterator, pensé que agregaría un par de métodos alternativos. En primer lugar, una clase muy simple que actúa como un proxy cadena:
class line {
std::string data;
public:
friend std::istream &operator>>(std::istream &is, line &l) {
std::getline(is, l.data);
return is;
}
operator std::string() const { return data; }
};
Con esto, todavía había leído utilizando un istream_iterator normal.Por ejemplo, para leer todas las líneas de un archivo en un vector de cadenas, podría utilizar algo como:
std::vector<std::string> lines;
std::copy(std::istream_iterator<line>(std::cin),
std::istream_iterator<line>(),
std::back_inserter(lines));
El punto crucial es que cuando estás leyendo algo, se especifica una línea - pero de lo contrario, solo tienes cadenas.
Otra posibilidad utiliza una parte de la biblioteca estándar que la mayoría de la gente apenas sabe que existe, sin mencionar que tiene un uso muy real. Cuando lee una cadena con el operador >>, la transmisión devuelve una cadena de caracteres hasta lo que la configuración regional de la secuencia dice que es un carácter de espacio en blanco. Especialmente si usted está haciendo un montón de trabajo que es todo alineación orientada, puede ser conveniente crear un escenario con una faceta ctype que sólo clasifica nueva línea como un espacio en blanco:
struct line_reader: std::ctype<char> {
line_reader(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
static std::vector<std::ctype_base::mask>
rc(table_size, std::ctype_base::mask());
rc['\n'] = std::ctype_base::space;
return &rc[0];
}
};
Para usar esto, usted imbuye la secuencia desde la que va a leer con una configuración regional utilizando esa faceta, luego solo lee cadenas normalmente, y el operador >> para una cadena siempre lee una línea completa. Por ejemplo, si quisiéramos leer en las líneas, y escribir las líneas únicas en forma ordenada, podríamos usar un código como éste:
int main() {
std::set<std::string> lines;
// Tell the stream to use our facet, so only '\n' is treated as a space.
std::cin.imbue(std::locale(std::locale(), new line_reader()));
std::copy(std::istream_iterator<std::string>(std::cin),
std::istream_iterator<std::string>(),
std::inserter(lines, lines.end()));
std::copy(lines.begin(), lines.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}
Tenga en cuenta que esto afecta a toda la entrada de la corriente. El uso de esto prácticamente descarta mezclar la entrada orientada a la línea con otra entrada (por ejemplo, leer un número de la transmisión usando stream>>my_integer
normalmente fallaría).
¿No es bueno mantener la línea en el alcance? Fuera del alcance no sirve de mucho, ya que terminará reteniendo el valor de la última línea o algo así. – cppLearner
@cppLearner: Buen punto, pero tal vez deberías poner esto en una función propia, por lo que la cadena utilizada temporalmente queda fuera de alcance de todos modos. – UncleBens
Siempre puede usar llaves vacías, en el caso de que haya una buena razón para limitar el alcance de la cadena, pero también una buena razón para que algún otro bit de código antes y/o después del bucle esté en la misma función. No creo que limitar el alcance deba determinar si usar "durante" o "mientras", lo que debería determinar si está esperando que algo sea falso (while), o atravesar algo que es conceptualmente un rango (para). Obviamente, la diferencia entre los dos es un límite difuso. Son lógicamente equivalentes, se trata de cómo concibes el ciclo. –