Jste zde

Zajímavosti z C++: Načtení celého vstupu do std::string v jednom příkazu

Včera jsem s kamarádem řešil, zda a jak lze v C++ načíst celý obsah vstupu do std::string v jediném příkazu. Pokud by to někoho zajímalo, tak odpověď dává následující krátký příspěvek.

Řešení

Ano, je to možné, a to následovně:

#include <iostream>
#include <iterator>
#include <string>
 
using namespace std;
 
int main() {
    string s((istreambuf_iterator<char>(cin)), istreambuf_iterator<char>());
}

Je použit dvouparametrový konstruktor string(input_iterator start, input_iterator end), kde start je iterátor ukazující na začátek vstupu a end je iterátor ukazující těsně za konec vstupu (já vím, zní to zajímavě, že u vstupu, u kterého nevíte, jak bude dlouhý, vytváříte iterátor ukazující za jeho konec :)). Jsou použity iterátory istreambuf_iterator<char>, které postupují znak po znaku, a to nezávisle na jeho hodnotě (viz dále). Jelikož chceme číst ze vstupu, tak prvnímu iterátoru předáme standardní proud cin. Volání istreambuf_iterator<char>() nám vytvoří onen iterátor ukazující znak za konec vstupu.

Na co si dát pozor

Je třeba si dát pozor na dvě věci. Za prvé, nelze použít iterátor istream_iterator, protože ten by způsobil, že by došlo k zahození všech bílých znaků ze vstupu (což ve většině případů nechcete).

string s((istream_iterator<char>(cin)), istream_iterator<char>()); // Zahodí bílé znaky na vstupu

Za druhé, zdánlivě nadbytečné závorky jsou opravdu nutné, jinak bychom místo objektu typu string deklarovali funkci (zájemce o bližší vysvětlení odkazuji zde). Schválně si můžete zkusit přeložit následující kód:

string s(istreambuf_iterator<char>(cin), istreambuf_iterator<char>()); // Deklarace funkce!

Pokud bychom nepoužili direktivu/deklaraci using a kvalifikovali bychom istreambuf_iterator jmenným prostorem std:: explicitně, problém by nenastal (jména formálních parametrů funkcí nemohou mít v názvu dvojtečky).

Přidat komentář