If you're learning C++, one surprisingly common source of confusion is input. Why does this: std::cin >> text; only read one word? Why does std::getline() sometimes seem to skip an input? And why does reading text from a file suddenly print every word on a separate line? The answer becomes much simpler once you understand that C++ has two different ideas here: reading a value and reading a line. That's also the idea behind my small header-only library, EasyIn. Reading one word with standard C++ Consider this: #include <iostream> #include <string> int main() { std::string name; std::cout << "Enter your name: "; std::cin >> name; std::cout << "Hello, " << name << '\n'; } If you enter: John Smith the variable only receives: John That's not a bug. The extraction operator: >> reads a value and treats whitespace as a separator. For a std::string, that effectively means: Read one whitespace-delimited word. Spaces, tabs and newlines separate values. This is useful for things such as: 25 180 75 because you can simply write: int age; int height; int weight; std::cin >> age >> height >> weight; But it isn't what you want when the input itself can contain spaces. Reading an entire line For that, C++ provides std::getline(): std::string fullname; std::getline(std::cin, fullname); Now: John Smith is stored as: John Smith Spaces inside the line are preserved. So conceptually: std::cin >> value; means: Read the next value. while: std::getline(std::cin, line); means: Read until the end of this line. That difference is important. The famous cin + getline problem Beginners often run into something like this: int age; std::string name; std::cin >> age; std::getline(std::cin, name); After entering the age, getline() can immediately consume the newline that was left behind. One common solution is: std::getline(std::cin >> std::ws, name); std::ws consumes leading whitespace before getline() begins reading the text. That is convenient, especially when switching from numeric input to line input. But there's an important detail: std::ws also removes other leading whitespace. That includes indentation and blank lines. Keep that in mind if you need to preserve the exact formatting of the input. Wrapping this with EasyIn I created EasyIn to make the common cases shorter and easier to understand. Instead of: std::cin >> age; you can write: easyin::input(age); And instead of: std::getline(std::cin >> std::ws, fullname); you can write: easyin::inputln(fullname); The names are deliberately simple: input() -> read one value inputln() -> read a line Using input() #include <string> #include "easyin.hpp" int main() { std::string name; easyin::input(name); } If the user enters: John Smith name becomes: John That's because EasyIn's input() uses normal C++ stream extraction internally. For numbers: int age; if (easyin::input(age)) { // Successful read } The function returns true when the read succeeds and false when it fails. Using inputln() If we actually want the full name: #include <string> #include "easyin.hpp" int main() { std::string fullname; easyin::inputln(fullname); } Entering: John Smith stores the entire line. So the choice is straightforward: Function Purpose input() Read one value inputln() Read a line of text Pairing EasyIn with C++23 print C++23 introduced the <print> header with std::print() and std::println(). That makes output considerably cleaner. Combined with EasyIn, a small console program can look like this: #include <print> #include <string> #include "easyin.hpp" using easyin::input; using easyin::inputln; int main() { int age{}; std::string fullname; std::print("Age: "); if (!input(age)) { std::println("Invalid age."); return 1; } std::print("Full name: "); if (!inputln(fullname)) { std::println("Could not read the name."); return 1; } std::println( "Hello, {}! You are {} years old.", fullname, age ); } Compare the important part: std::print("Age: "); input(age); std::print("Full name: "); inputln(fullname); std::println("Hello, {}!", fullname); Modern C++ doesn't necessarily have to mean pages of syntax for a simple console program. C++ remains a compiled, native language while its higher-level interfaces can still be designed to be readable. That's one of the reasons I wanted to experiment with EasyIn. Reading from a text file The same distinction applies to files. Suppose sample.txt contains: Hello, world! This is a simple text file. You can read it using C++ fstream. Each line contains plain text. Happy coding! We can read it with EasyIn by passing an input stream as the second argument: #include <fstream> #include <print> #include <string> #include "easyin.hpp" int main() { std::ifstream file("sample.txt"); if (!file.is_open()) { std::println("Could not open sample.txt."); return 1; } std::string line; while (easyin::inputln(line, file)) { std::println("{}", line); } } The interesting line is: easyin::inputln(line, file) Normally inputln() reads from std::cin. By providing file, we tell it to read from that stream instead. What happens if we use input() instead? This: while (easyin::input(line, file)) { std::println("{}", line); } does not read one line at a time. It reads one whitespace-delimited string at a time. Given: Hello, world! the reads would be approximately: Hello, world! And because println() adds a newline after every output, you'd see: Hello, world! This is a simple text file. Again, nothing is broken. input() is doing exactly what >> normally does. If you want lines, use inputln(). One important limitation EasyIn's current inputln() implementation uses: std::getline(in >> std::ws, var); That makes switching between things like: input(age); inputln(name); convenient because leftover whitespace is handled automatically. But it also means leading whitespace and blank lines are skipped. For example, if exact indentation matters: indented text another line EasyIn's inputln() is not intended to preserve that formatting exactly. For exact line-by-line file processing, use standard std::getline() directly: std::string line; while (std::getline(file, line)) { std::println("{}", line); } A wrapper should make common operations easier, not hide important behavior. Why build something this small? Python is often recommended to beginners partly because code such as: name = input() print(f"Hello, {name}!") is immediately readable. Moving into C++ introduces streams, extraction operators, getline, stream state, leftover newlines and error handling very quickly. Those concepts are useful and C++ programmers should understand them. But learning the underlying mechanism and having a convenient interface aren't mutually exclusive. C++23 already moved output in this direction with: std::print() std::println() EasyIn is my experiment with applying a similarly simple interface to the input side: input() inputln() It doesn't replace C++ streams. It wraps common stream operations while keeping them accessible underneath. And once you understand the distinction between: value input and: line input a lot of seemingly strange C++ input behavior starts making sense. EasyIn is a small open-source, header-only C++ library. GitHub: EasyIn Video introduction on YouTube If you're learning C++, I'd also recommend experimenting with the underlying std::cin, operator>>, and std::getline() functions directly. Understanding what EasyIn wraps is ultimately more useful than simply memorizing the wrapper functions.