C++ print a sequence

 

This is a post for C++ beginners. Not an easy role in the world of programming languages. But, I know it can be a rewarding one.

So, this is the situation. You are into intensive C++ std lib sampling and learning. You have a lot of little snippets. One thing has annoyed you a lot, but you have given up on it. You will do it later.

How to print a C++ sequence (or range) from one single and nice generic function.  Easy. But with no trailing comma. Not easy. Not hard either. That function finalized by you would be proof you are advancing.

In case you want such a function, to start with it, for the output like on the image above, here is the code.

The discussion comes later. Do not ignore it.

// (c) 2019/2020 by dbj@dbj.org
// Licence CC BY SA 4.0
// assumption is you can place this in some header of yours
// with namespace and required includes

// print a sequence
// arguments are two iterators
// pointing to it
// note: using std::cout is not recommended
template<typename Iterator >
 inline void sequence_print( 
    Iterator begin_ , 
    Iterator end_ , 
    bool show_size = true ) 
{
   using namespace std;
 // local size since there is no sequence 
 // object on which to call it
 auto size_ = [&] { 
   return  size_t( distance( begin_, end_ ) );  
 };
 // if size is requested, show it
 if (show_size) cout << " sequence [size:" << size_() << "]";
 cout << " {";
 auto walker = begin_ ;
 if (walker != end_ )
 {
   // first sequence element
   // no leading comma
    cout << " " << *walker; 
	walker++;
   // other elements, if any
    // with a leading comma
    while (walker != end_ ) {
	cout << " , " << *walker;
    // operator '++' advances the iterator
    // logically to the 'right'
    // see the diagram below
    walker++;
    }
 }
   cout << " }";
}

// print a sequence with a comma in between elements
// the only requirement is the 'sequence' conforms
// to the concept as on the diagram bellow
// sequence size is also printed by default
template<typename Sequence >
  inline void sequence_print(Sequence const & seq_, bool show_size = true ) {
   using namespace std;
   sequence_print( begin(seq_) , end( seq_ ) , show_size );
}

This ‘thing’ above can print anything to which begin and end can be found. For example

// print native array
char charr[]{'A','B','C','D'};
sequence_print( charr );
// print std::string		
sequence_print(string{"STD::STRING"});
// print std::list
sequence_print(std::list{1,2,3});
// and so on

Explanation

I said “begin and end can be found”. This is different from “has begin() and end() methods”. Here is the (sort of a official) diagram representing a sequence

A sequence concept
A sequence concept. Iterators including.

There are (generic) std::begin() and std::end() functions. They return those two begin and end iterators as on the diagram above. That same diagram and concept of a sequence it represents, do apply to native arrays and all the types that can be logically visualized as a sequence.

We operate using this knowledge. Key to C++ is your ability to think abstract.  Not to get pulled down into the low-level details of (for example) implementations of std lib containers. That comes later. And is not mandatory.

That is why sequence_print looks simple. It is a high level code and algorithm , hiding a lot of complexity.

  1. think
  2. think abstract

I was deliberately vague. Don’t hesitate to ask in the comments bellow. I am especially interested how you might improve this code.

Hint: here is my hint, but ultimately I would like to see your version using std::format.