Kirjautuminen

Haku

Tehtävät

Koodit: C++: Funktioita virtojen ympärille

Kirjoittaja: Metabolix

Kirjoitettu: 17.02.2013 – 17.02.2013

Tagit: ohjelmointitavat, teksti, kirjasto, koodi näytille, vinkki

Seuraava IO-luokka sisältää muutaman funktion, joilla voi lukea syötettä ja tulostaa arvoja C++:n virtoihin käyttämättä itse merkintöjä << ja >>. Luokasta ei ole varsinaista hyötyä, mutta se voi tuntua tutummalta esimerkiksi Javaan tai Pythoniin tottuneiden mielestä. Lisäksi luokan avulla tulosteen ja syötteen voi laittaa helposti samalle koodiriville, ja luokassa on myös funktio syöterivin loppuosan ohittamiseen ja muuten vain kokonaisten rivien ohittamiseen.

Luokan print-funktiossa on myös esimerkki C++11:n uusista malleista, joille voi antaa vaihtelevan määrän parametreja: print-funktio tulostaa yhden arvon ja antaa loput sitten rekursiivisesti uudelle print-kierrokselle; kun arvot loppuvat, kutsutaankin toista print-funktiota, jolla ei ole parametreja ja jossa vain viimeistellään tulostus.

IO-luokka

#include <iostream>
#include <limits>

/**
 * Rajapinta syöte- ja tulostevirran käsittelyyn.
 */
struct IO {
	/** @var Syötevirta. */
	std::istream& input;

	/** @var Tulostevirta. */
	std::ostream& output;

	/**
	 * Uudelle IO-oliolle tarvitaan syöte- ja tulostevirrat.
	 */
	IO(std::istream& input_, std::ostream& output_):
		input(input_), output(output_) {
		// Käsketään syötevirran heittää poikkeus virhetilanteessa.
		input.exceptions(std::ios::failbit | std::ios::badbit | std::ios::eofbit);
	}

	/**
	 * C++11: Tulostaa arvoja. Vanhemmille kääntäjille pitää tehdä versio,
	 * joka ottaa vain yhden parametrin ja sen jälkeen tekee samat jutut,
	 * jotka nyt ovat myöhemmässä print-funktiossa.
	 */
	template <typename T, typename... Args>
	IO& print(const T& t, Args... args) {
		// Tulostetaan ensimmäinen arvo ja rekursiolla loput.
		output << t;
		return print(args...);
	}

	/**
	 * Käsketään tulostevirran todella tulostaa sisältö.
	 * Edellisen print-funktion rekursio päättyy tähän.
	 */
	IO& print() {
		output << std::flush;
		return *this;
	}

	/**
	 * Ohittaa merkit seuraavaan rivinvaihtoon asti.
	 */
	IO& skipLineEnd() {
		input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
		return *this;
	}

	/**
	 * Lukee ja palauttaa seuraavan rivin.
	 */
	std::string nextLine() {
		std::string tmp;
		std::getline(input, tmp);
		return tmp;
	}

	/**
	 * Lukee yhden arvon ja ohittaa loput rivistä.
	 */
	template <typename T> T nextLine() {
		T tmp = next<T>();
		skipLineEnd();
		return tmp;
	}

	/**
	 * Lukee yhden arvon.
	 */
	template <typename T> T next() {
		T tmp;
		input >> tmp;
		return tmp;
	}
};

Esimerkki

int main() {
	// Luodaan IO-olio, joka käyttää standardivirtoja.
	IO io(std::cin, std::cout);

	// Tulostetaan kysymys ja luetaan vastaus (koko rivi).
	std::string nimi = io.print("Kuka olet? ").nextLine();

	// Tässä luetaan int-tyyppinen vastaus ja ohitetaan loput rivistä.
	int ika = io.print("Kuinka vanha olet? ").nextLine<int>();

	// Nyt luetaan kaksi float-arvoa, jotka voivat olla samalla rivillä;
	// rivin loppu ohitetaan vasta toisen luvun jälkeen.
	io.print("Anna paino ja pituus välillä erotettuna: ");
	float massa = io.next<float>();
	float pituus = io.nextLine<float>();

	// Oletetaan, että pituus on alle 10 metriä, jolloin
	// tämä silmukka muuttaa sentit ja millit metreiksi.
	while (pituus > 10) {
		pituus /= 10;
	}

	// Tulostetaan kaikenlaista.
	io.print(
		nimi, " on ", ika, " vuotta vanha.\n",
		"Pituus on ", pituus, " metriä ja massa ", massa, " kiloa, ",
		"joten painoindeksi eli BMI on ", massa / pituus / pituus, ".\n"
	);

	// Odotetaan vielä yhtä enteriä eli rivinvaihtoa syötteessä.
	io.print("Paina enter.").skipLineEnd();
}

Kirjoita kommentti

Muista lukea kirjoitusohjeet.
Tietoa sivustosta