How to use something like s.end() in for loop with auto?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



How to use something like s.end() in for loop with auto?



I have a below program, I want to see how to condition on last element in the container when using auto in C++11, that's why this question.


#include <iostream>
#include <set>

using namespace std;

void show(set<string>& s)
cout << "<";
for (const auto &e: s)
if (e != s.end()) // This is WRONG -- results in compilation error !!
cout << e << ",";
else
cout << e;
cout << ">" << endl;


int main(int argc, char *argv)
set <string> s = "a", "e", "i", "o" ;
show(s);
return 0;



above program outputs <a,e,i,o,>


<a,e,i,o,>



I tried to use s.end() in the for loop in the show(), but compilation fails.


s.end()


for


show()



desired output :


<a,e,i,o>





I am currently developing a library that allows to simply write something like std::copy(s.cbegin(), s.cend(), nstd::join_iterator<std::string>(std::cout, ", "));
– bipll
Aug 10 at 16:29


std::copy(s.cbegin(), s.cend(), nstd::join_iterator<std::string>(std::cout, ", "));





@bipll See std::experimental::ostream_joiner
– Justin
Aug 10 at 16:37


std::experimental::ostream_joiner





@Justin Sure, except for with my lib you can also write, for instance, std::vector<int> sink; nstd::join_iterator<std::vector<int>> i(sink, 42); and it will concatenate vectors inserting 42 inbetween. This particular class is somewhat pythonic in number of options it provides.
– bipll
Aug 10 at 18:46



std::vector<int> sink; nstd::join_iterator<std::vector<int>> i(sink, 42);




4 Answers
4



Use this:


if (&e != &*s.rbegin())



Or even better, print comma before an element. I assume it could be slightly faster.


if (&e != &*s.begin())
cout << "," << e;
else
cout << e;





Thanks, this works, but any other cleaner way to do this ?
– Onkar N Mahajan
Aug 10 at 16:20





@OnkarNMahajan IMO it's clean enough, especially the second option. Here is an another option: bool first = 1; for (...) if (first) first = 0; else std::cout << ','; std::cout << e;.
– HolyBlackCat
Aug 10 at 16:22



bool first = 1; for (...) if (first) first = 0; else std::cout << ','; std::cout << e;





sure, thanks for taking time to clarify my doubts.
– Onkar N Mahajan
Aug 10 at 16:25





You don't need to use & when comparing, also you should use const iterator crbegin().
– Mateusz Wojtczak
Aug 10 at 17:02





@MateuszWojtczak Comparing addresses is faster. Also, if it was a different container (that allows duplicate elements), omitting & would lead to incorrect results. "you should use const iterator crbegin" I'd say it's a matter of preference. In this case it doesn't make a big difference.
– HolyBlackCat
Aug 10 at 18:19


&



The range based for loops sacrifice power for simplicity. Making use of auto looping over iterators is less fiddly than it used to be:


auto


for (auto it = s.begin(); it != s.end(); ++it)

if (std::next(it) != s.end())
cout << e << ",";
else
cout << e;



It'd be nice if there was a portable way to get your current position in a range based for loop but until that gets added to the standard you'll just have to make the choice between simplicity and flexibility.



I think, the shortest way is to test a 'bool' variable before adding a comma to the output stream. The following code should fits your needs.


#include<iostream>
#include<set>
using namespace std;

void show(set<string>& s);

int main(int argc, char *argv)
set <string> s = "a", "e", "i", "o" ;
show(s);
return 0;


void show(set<string>& s)
cout<<'<';
bool add_comma=false;
for (const auto& e: s)
if (add_comma)cout<<',';
cout<<e;
add_comma=true;

cout<<'>';



You usually get more readable code by printing first element outside of the main loop.


void show(const set<string>& s)
cout << "<";
auto it = s.begin();
if (it != s.end())
cout << *it++;

for (; it != s.end(); ++it)
cout << "," << *it;

cout << ">" << endl;






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard