0

I'm relearning C++ and I found myself often writing pieces of code like this:

vector<string> Text;
string Line;

while (getline(cin, Line))
{
    Text.push_back(Line);
}

I was wondering if there is a more compact way to write the loop using only basic features (no user-written functions, for example) - more or less, putting everything in the condition?

Andrea Bocco
  • 792
  • 5
  • 14
  • 5
    loop with single instruction, how this can be more compact? Empty loop? – Marek R Aug 08 '18 at 12:33
  • This is as basic as it gets. It reads from `cin` input stream until `getline()` fails. – Yiğit Aras Tunalı Aug 08 '18 at 12:43
  • 2
    *Why* do you want it to be more compact? What advantage does that give you? It certainly won't make it any more readable! – Toby Speight Aug 08 '18 at 12:43
  • "Compact syntax" and "simple code" are not always (rarely?!) the same thing. So which one do you want? – Lightness Races in Orbit Aug 08 '18 at 13:30
  • If you want compact, use `std::string::reserve` and `std::cin::read`. This will read the file into one large string (provided you reserved enough space), thus the data is more *compact*, leaving less holes or gaps in memory. Also, two statements, thus being more *compact* in the source code. Search the internet for "memory mapped files", append your operating system name to the keywords. – Thomas Matthews Aug 08 '18 at 14:31
  • For more compact, search the internet for "c++ text compression". – Thomas Matthews Aug 08 '18 at 14:32

5 Answers5

10

You can use a for loop. We can declare Line in the variable declaration part and use the condition and increment parts to read and place the line. That gives you

for(string Line; getline(cin, Line); Text.push_back(Line));
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • More compact? And readability? We have a read function, result for comparisons of a loop and a function inside. So writing it as for/do while/while or whatever will not make the thing better! – Klaus Aug 08 '18 at 12:41
  • @Klaus The user doesn't want better, they want more compact – NathanOliver Aug 08 '18 at 12:43
  • Ha. I really like this. It also doesn't require a hack to deal with `push_back` being `void`. – Bathsheba Aug 08 '18 at 12:45
  • @Bathsheba Yeah. I was thinking if using your solution then I remembered I could just do it in the increment step. – NathanOliver Aug 08 '18 at 12:46
  • Is meaning "compact" reducing the number of lines or number of characters? ;) Not clear requirements if your code is the solution ;) – Klaus Aug 08 '18 at 12:46
  • 2
    @Klaus: There does not exist a solution to something that doesn't have a problem, such as the code that the OP presents ;-) – Bathsheba Aug 08 '18 at 12:47
2

Well, at the expense of some obfuscation,

while (getline(cin, Line) && (Text.push_back(Line), 1));

would do it: note the use of the expression separator operator which, informally speaking, "converts" the void return type of push_back to an int so enabling its use with the short-circuiting &&.

But as a rule of thumb, work with the language, not against it. My answer is doing the latter. The way you present the code in your question is adequate.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
2

more or less, putting everything in the condition?

You can do this

while (getline(cin, Line) && (Text.push_back(Line),true)) {}

It works because && is short-circuited and because the comma-operator evaluates the first operand, discards the result and returns the result of the second operand.

So it is possible, but why would you want to do that? Making code as dense as possible is rarely good for readability (actually your original code is more readable and uses less characters).

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
1

At the risk of "but that is exactly OP's code!", I would personally favor this version if this is the entire body of a scope (e.g. function that parses the text):

vector<string> Text;
string Line;

while (getline(cin, Line))
  Text.push_back(Line);

Alternatively, if part of a larger scope, I would probably group all four lines together and add empty lines before and after for visual coherence (and maybe add a short comment before it):

// [lots of other code]

// Gather input from cin.
vector<string> Text;
string Line;
while (getline(cin, Line))
  Text.push_back(Line);

// [lots of other code]

I am aware that this introduces no clever tricks, but this is the most compact and readable form of the given code, at least to me.

If you wanted compactness above all else, you could choose garbage variables, omit all unnecessary whitespace and even alias the types beforehand (since we are "often writing" this kind of code this is a one-off) to, say, V<S> t;S l;while(getline(cin,l))t.push_back(l); but nobody wants to read that.

So clearly there is more than compactness at play. As for me, I'm looking to keep noise to a minimum while retaining intuitive readability, and I would suggest this is an agreeable goal.

I would never use the "throw everything into the loop condition" suggestions because that very much breaks how I expect code to be structured: The main purpose of your loop goes into the loop body. You may disagree/have different expectations, but in my eyes everything else is just an attempt to show off your minifying skills, it does not produce good code.

The above accomplishes just that: The braces are noise for this simple operation, and the important part stands out as the loop body. "But is getline not also important?" - It is, and I would honestly prefer a version where it is in the loop body, such as a hypothetical

vector<string> Text;
while (cin.hasLine())
  Text.push_back(readLine(cin));

This would be an ideal loop to me: The condition only checks for termination and the loop body is only the operation we want to repeat.

Even better would be a standard algorithm, but I unaware of any that would help here (ranges or boost might provide, I don't know).


On a more abstract level, if OP frequently writes this exact code, it should obviously be a separate function. But even if not, the "lots of other code" example would benefit from that abstraction too.

Max Langhof
  • 23,383
  • 5
  • 39
  • 72
-3

Loop with a single instruction. you can write it in one line but I don't recommend it

while (getline(cin, Line)) Text.push_back(Line);
Ludovic
  • 25
  • 1
  • 11