Ce qui suit se veut un petit truc simple pour consommer du texte ligne par ligne avec un effort minimal. À titre d'exemple, ce qui suit afficherait chaque ligne du fichier in.txt sur la sortie standard :
// ... inclusions et using ...
int main() {
ifstream in{ "in.txt" };
for (const auto & s : lignes{ in }) {
cout << s << endl;
}
}
L'idée derrière cette manoeuvre :
La classe lignes n'est pas un conteneur, mais elle exposera des services nommés begin() et end() pour qu'une instance de lignes s'intègre bien dans une répétitive for sur des intervalles. Notez que j'aurais aussi pu spécialiser std::begin() et std::end() sur lignes, une option que je n'ai pas eu le temps d'explorer. Sur le plan structurel, un lignes contient à la fois une référence sur le flux d'où sont consommées les lignes, et la ligne la plus récemment lue. |
|
Lors de la construction d'une instance de lignes, je consomme une première ligne. Ceci peut placer l'objet en question dans un état d'erreur, équivalent à un objet modélisant un fichier vide. |
|
L'essentiel du travail est réalisé par la classe lignes::iterator. Cette classe modélise le concept de ForwardIterator, et ne permet qu'une lecture du début à la fin, ce qui permet de consommer des lignes de texte au clavier ou sur un lien réseau. |
|
Pour faire son travail, un lignes::iterator contient un pointeur sur le lignes qui lui sert de source de données (et qui peut être nul). Le constructeur prenant en paramètre un lignes* est privé, mais lignes est amie de lignes::iterator donc tout se tient. |
|
Puisque lignes ne modélise que des lignes de texte, lignes::iterator n'a pas besoin d'exposer l'opérateur -> et peut se limiter à offrir l'opérateur *. |
|
L'opérateur == est plus complexe qu'on pourrait s'y attendre, pour tenir compte du fait que typiquement, la comparaison entre deux instances de lignes::iterator impliquera au moins une instance qui contiendra un src qui sera nul. |
|
Enfin, les opérateurs ++, préfixe et suffixe, consomment une ligne de la source. Le service lignes::read_one() est privé dans lignes, mais heureusement lignes::iterator est ami de lignes. |
|
Enfin, les services clés de lignes sont begin() et end(), qui retournent des lignes::iterator convenablement construits. |
|
Voilà!