How does this printing code work? - c++

I found this code somewhere. It prints "abcd" to the screen but in a weird way. I would like someone to tell me how it works:
#include <iostream>
#include <sstream>
class X
{
typedef std::istreambuf_iterator<char> Iter;
Iter it;
public:
X(std::streambuf* p) : it(p) { }
Iter begin()
{ return it; }
Iter end()
{ return Iter(); }
};
void printbuf(X x, std::ostreambuf_iterator<char> it)
{
for (auto c : x)
{
*it = c;
}
}
int main()
{
std::stringbuf buf("abcd", std::ios_base::in | std::ios_base::out);
printbuf(&buf, std::cout);
}

We have a class X which encapsulates an istreambuf_iterator<char>. This is an iterator type which allows us to treat a stream buffer as an iterator range for standard algorithms.
class X
{
typedef std::istreambuf_iterator<char> Iter;
Iter it;
public:
The class is constructible from a pointer to a stream buffer instance.
X(std::streambuf* p) : it(p) { }
It exposes begin() and end() member functions to allow it to be used with the range-based for loop.
Iter begin()
{ return it; }
Iter end()
{ return Iter(); }
};
printbuf() is a function which accepts an instance of our range class X, as well as an ostreambuf_iterator<char>, which—you guessed it—allows us to use an output stream buffer as an output iterator.
void printbuf(X x, std::ostreambuf_iterator<char> it)
{
So we iterate over every character in the input range.
for (auto c : x)
{
If you haven’t dealt with output iterators before, you can think of them as an object resembling a pointer, to which you write values using dereference and assignment. back_insert_iterator is a commonly used output iterator, for building containers—you usually construct it using back_inserter. But I digress.
We copy each character to the output iterator.
*it = c;
}
}
int main()
{
Here we construct a string buffer, which is both an input and output stream buffer. We only use the input capability in this example.
std::stringbuf buf("abcd", std::ios_base::in | std::ios_base::out);
Now we use an implicitly-constructed X instance to treat the string buffer as an iterator range. Then we copy that range to an output stream buffer iterator—also implicitly constructed—to std::cout.
printbuf(&buf, std::cout);
}
The effect is that we’re looping over each character in the buffer and copying it to standard output.

printbuf(&buf, std::cout);
Passing std::stringbuf* as the first paramter causes an implicit construction of X to match printbuf()
And also for the second parameter, an implicit
contruction occurs, an instance of std::ostreambuf_iterator<char> is created from std::cout (std::ostream)
void printbuf(X x, std::ostreambuf_iterator<char> it)
{
for (auto c : x)
{
*it = c;
}
}
In printbuf, the foreach loop (range based for loop) uses X::begin() and X::end() to loop over all characters in that wrapped std::stringbuf and writes them to std::cout via the std::ostreambuf_iterator (it)

Related

How does std::reverse_iterator hold one before begin?

This is a code example using std::reverse_iterator:
template<typename T, size_t SIZE>
class Stack {
T arr[SIZE];
size_t pos = 0;
public:
T pop() {
return arr[--pos];
}
Stack& push(const T& t) {
arr[pos++] = t;
return *this;
}
auto begin() {
return std::reverse_iterator(arr+pos);
}
auto end() {
return std::reverse_iterator(arr);
// ^ does reverse_iterator take this `one back`? how?
}
};
int main() {
Stack<int, 4> s;
s.push(5).push(15).push(25).push(35);
for(int val: s) {
std::cout << val << ' ';
}
}
// output is as expected: 35 25 15 5
When using std::reverse_iterator as an adaptor for another iterator, the newly adapted end shall be one before the original begin. However calling std::prev on begin is UB.
How does std::reverse_iterator hold one before begin?
Initialization of std::reverse_iterator from an iterator does not decrease the iterator upon initialization, as it would then be UB when sending begin to it (one cannot assume that std::prev(begin) is a valid call).
The trick is simple, std::reverse_iterator holds the original iterator passed to it, without modifying it. Only when it is being dereferenced it peeks back to the actual value. So in a way the iterator is pointing inside to the next element, from which it can get the current.
It would look something like:
// partial possible implementation of reverse_iterator for demo purpose
template<typename Itr>
class reverse_iterator {
Itr itr;
public:
constexpr explicit reverse_iterator(Itr itr): itr(itr) {}
constexpr auto& operator*() {
return *std::prev(itr); // <== only here we peek back
}
constexpr auto& operator++() {
--itr;
return *this;
}
friend bool operator!=(reverse_iterator<Itr> a, reverse_iterator<Itr> b) {
return a.itr != b.itr;
}
};
This is however an internal implementation detail (and can be in fact implemented in other similar manners). The user of std::reverse_iterator shall not be concerned with how it is implemented.

How to make std::istream_iterator read only until the end of line?

Having the following piece of code:
std::vector<int64> values;
std::copy(
std::istream_iterator<int64>(std::cin),
std::istream_iterator<int64>(),
std::back_inserter(values)
);
I'd like to make it read the input stream only until the end of line. How can I do that with std::istream_iterator?
You can't do it with std::istream_iterator.
But it is relatively easy to write an input iterator.
#include <iterator>
#include <iostream>
#include <sstream>
#include <vector>
#include <cctype>
template<typename T>
class istream_line_iterator: public std::iterator<std::input_iterator_tag, T>
{
std::istream* stream;
public:
// Creating from a stream or the end iterator.
istream_line_iterator(std::istream& s): stream(&s) {dropLeadingSpace();}
istream_line_iterator(): stream(nullptr) {}
// Copy
istream_line_iterator(istream_line_iterator const& copy): stream(copy.stream) {}
istream_line_iterator& operator=(istream_line_iterator const& copy) {stream = copy.stream;return *this;}
// The only valid comparison is against the end() iterator.
// All other iterator comparisons return false.
bool operator==(istream_line_iterator const& rhs) const {return stream == nullptr && rhs.stream == nullptr;}
bool operator!=(istream_line_iterator const& rhs) const {return !(*this == rhs);}
// Geting the value modifies the stream and returns the value.
// Note: Reading from the end() iterator is undefined behavior.
T operator*() const {T value;(*stream) >> value;return value;}
T* operator->() const; // Not sure I want to implement this.
// Input streams are funny.
// Does not matter if you do a pre or post increment. The underlying stream has changed.
// So the effect is the same.
istream_line_iterator& operator++() {dropLeadingSpace();return *this;}
istream_line_iterator& operator++(int) {dropLeadingSpace();return *this;}
private:
void dropLeadingSpace()
{
// Only called from constructor and ++ operator.
// Note calling this on end iterator is undefined behavior.
char c;
while((*stream) >> std::noskipws >> c) {
if (c == '\n') {
// End of line. So mark the iterator as reaching end.
stream = nullptr;
return;
}
if (!std::isspace(c)) {
// Found a non space character so put it back
stream->putback(c);
return;
}
}
// End of stream. Mark the iterator as reaching the end.
stream = nullptr;
}
};
int main()
{
std::stringstream s{"0 1 2 3 4 5 6 7 8 9 10\n11 12 13 14 15 16\n17 18 19"};
std::vector<int> d{istream_line_iterator<int>(s), istream_line_iterator<int>()};
for(auto v: d) {
std::cout << "V: " << v << "\n";
}
}
Running:
> g++ -std=c++17 main.cpp
> ./a.out
V: 0
V: 1
V: 2
V: 3
V: 4
V: 5
V: 6
V: 7
V: 8
V: 9
V: 10
If you want the functionality without adding a std::getline or std::stringstream, you can change the character classification of the stream so that a newline is not considered discardable whitespace. Here is a minimal example:
struct set_newline_as_ws : std::ctype<char> {
static const mask* make_table( std::ctype_base::mask m ) {
static std::vector<mask> v(classic_table(), classic_table() + table_size);
v['\n'] &= m;
return &v[0];
}
set_newline_as_ws( bool skip, std::size_t refs = 0 ) : ctype(make_table(skip ? ~space : space), false, refs) {}
};
std::istream& skipnewline( std::istream& is ) {
is.imbue(std::locale(is.getloc(), new std::ctype<char>));
return is;
}
std::istream& noskipnewline( std::istream& is ) {
is.imbue(std::locale(is.getloc(), new set_newline_as_ws(true)));
return is;
}
int main() {
std::vector<int64> values;
std::cin >> noskipnewline;
std::copy(
std::istream_iterator<int64>(std::cin),
std::istream_iterator<int64>(),
std::back_inserter(values)
);
std::cin >> skipnewline;
}
Adapted from an earlier answer to a similar question (here):
#include <vector>
#include <algorithm>
#include <string>
#include <iterator>
namespace detail
{
class Line : public std::string
{
friend std::istream & operator>>(std::istream & is, Line & line)
{
return std::getline(is, line);
}
};
}
template<class OutIt>
void read_lines(std::istream& is, OutIt dest)
{
typedef std::istream_iterator<detail::Line> InIt;
std::copy_n(InIt(is), 1, dest);
}
int main()
{
std::vector<std::string> v;
read_lines(std::cin, std::back_inserter(v));
return 0;
}
This code should take only one line and saves it into the vector v. This is thanks to the use of std::copy_n function which takes the number of elements-to-be-copied as input. There is a quirk, though, reported here. Depending on your platform, one or two lines will be read even though only the first one will be saved into v.
That being said, if you want to make it fail-safe, you can just implement your own copy_n(...) function, like so:
template<class InIt, class Range, class OutIt>
OutIt own_copy_n(InIt first, Range count, OutIt dest)
{
*dest = *first;
while (0 < --count)
*++dest = *++first;
return (++dest);
}
Then instead of using std::copy_n(...) in you code, you can use own_copy_n(...).
This way you'll be sure you'll have to input one line only, and that that line will be saved into your vector v.
It is impossible to change istream_iterator in this way, because it has no knowledge of newlines, or even of characters, for that matter. It only knows about int64(Or whatever type you instantiated it with) and if the stream ended or failed (When it then will return false on operator bool()).
This means that our point of customization must be the actual stream.
The stream object is actually just a wrapper around a std::basic_streambuf. The streambuf will spit out characters until it finds an EOF. You can simply adapt it to return an EOF once it finds a newline, then the stream will temporarily treat that as the end of stream.
Doing this is easy: The streambuf object is accessible through the member funtion rdbuf(). You can just replace the buffer with your custom one using this function. To have it continue reading after the newline when you're done, you can just return the original std::basic_streambuf back to the stream.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <streambuf>
#include <vector>
// This is our custom std::basic_streambuf object.
// We chose the underflow function as our point of customization, because
// it is there that the action is happening: it is this function that
// that is responsible for reading more data from the stream.
class newline_buf : public std::streambuf {
std::streambuf* src;
char ch; // single-byte buffer
protected:
int underflow() {
if( (ch= src->sbumpc()) == '\n') {
return traits_type::eof(); // return EOF on new line.
}
setg(&ch, &ch, &ch+1); // make one read position available
return ch; // may also return EOF by the regular means
}
public:
newline_buf(std::streambuf* buf) : src(buf) {
setg(&ch, &ch+1, &ch+1); // buffer is initially full
}
};
int main() {
// testing with a stringstream to make things easier to reproduce.
// Should work fine with any type of input stream.
std::istringstream iss(R"(12345 12345 12345
67890 67890 67890)");
// We store the original rdbuf so we can recover it later.
auto original_rdbuf = iss.rdbuf();
newline_buf buf(original_rdbuf);
iss.basic_ios::rdbuf(&buf);
// Do the copy and then recover the original rdbuf
std::copy(std::istream_iterator<int>(iss), std::istream_iterator<int>(), std::ostream_iterator<int>(std::cout, " "));
iss.basic_ios::rdbuf(original_rdbuf);
// You can try doing a new copy, just to convince yourself that the stream is still in a valid state.
//std::copy(std::istream_iterator<int>(iss), std::istream_iterator<int>(), std::ostream_iterator<int>(std::cout, " "));
}
See it live!

Is there a standard C++ iterator for C strings?

Sometimes I need to pass a C string to a function using the common C++ iterator range interface [first, last). Is there a standard C++ iterator class for those cases, or a standard way of doing it without having to copy the string or call strlen()?
EDIT:
I know I can use a pointer as an iterator, but I would have to know where the string ends, what would require me to call strlen().
EDIT2:
While I didn't know if such iterator is standardized, I certainly know it is possible. Responding to the sarcastic answers and comments, this is the stub (incomplete, untested):
class CStringIterator
{
public:
CStringIterator(char *str=nullptr):
ptr(str)
{}
bool operator==(const CStringIterator& other) const
{
if(other.ptr) {
return ptr == other.ptr;
} else {
return !*ptr;
}
}
/* ... operator++ and other iterator stuff */
private:
char *ptr;
};
EDIT3:
Specifically, I am interested in a forward iterator, because I want to avoid to iterate over the sring twice, when I know the algorithm will only have to do it once.
There isn't any explicit iterator class, but regular raw pointers are valid iterators as well. Problem with C-strings, though, is that they do not come with a native end iterator, which makes them unusable in range based for loops – directly at least...
You might like to try the following template, though:
template <typename T>
class Range
{
T* b;
public:
class Sentinel
{
friend class Range;
Sentinel() { }
friend bool operator!=(T* t, Sentinel) { return *t; }
public:
Sentinel(Sentinel const& o) { }
};
Range(T* begin)
: b(begin)
{ }
T* begin() { return b; }
Sentinel end() { return Sentinel(); }
};
Usage:
for(auto c : Range<char const>("hello world"))
{
std::cout << c << std::endl;
}
It originally was designed to iterate over null-terminated argv of main, but works with any pointer to null terminated array – which a C-string is as well...
Secret is comparing against the sentinel, which actually does a totally different comparison (current pointer pointing the terminating null (pointer))...
Edit: Pre-C++17 variant:
template <typename T>
class Range
{
T* b;
public:
class Wrapper
{
friend class Range;
T* t;
Wrapper(T* t) : t(t) { }
public:
Wrapper(Wrapper const& o) : t(o.t) { }
Wrapper operator++() { ++t; return *this; }
bool operator!=(Wrapper const& o) const { return *t; }
T operator*() { return *t; }
};
Range(T* begin)
: b(begin)
{ }
Wrapper begin() { return Wrapper(b); }
Wrapper end() { return Wrapper(nullptr); }
};
Actually, yes - sort of. In c++17.
C++17 introduces std::string_view which can be constructed from a c-style string.
std::string_view is a random access (proxy) container which of course fully supports iterators.
Note that although constructing a string_view from a const char* will theoretically call std::strlen, the compiler is allowed to (and gcc certainly does) elide the call when it knows the length of the string at compile time.
Example:
#include <string_view>
#include <iostream>
template<class Pointer>
struct pointer_span
{
using iterator = Pointer;
pointer_span(iterator first, std::size_t size)
: begin_(first)
, end_(first + size)
{
}
iterator begin() const { return begin_; }
iterator end() const { return end_; }
iterator begin_, end_;
};
int main(int argc, char** argv)
{
for(auto&& ztr : pointer_span(argv, argc))
{
const char* sep = "";
for (auto ch : std::string_view(ztr))
{
std::cout << sep << ch;
sep = " ";
}
std::cout << std::endl;
}
}
See the example output here
Is there a standard C++ iterator for C strings?
Yes. A pointer is an iterator for an array. C strings are (null terminated) arrays of char. Therefore char* is an iterator for a C string.
... using the common C++ iterator range interface [first, last)
Just like with all other iterators, to have a range, you need to have an end iterator.
If you know or can assume that an array fully contains the string and nothing more, then you can get the iterator range in constant time using std::begin(arr) (std::begin is redundant for C arrays which decay to the pointer anyway, but nice for symmetry) and std::end(arr) - 1. Otherwise you can use pointer arithmetic with offsets within the array.
A little bit of care must be taken to account for the null terminator. One must remember that the full range of the array contains the null terminator of the string. If you want the iterator range to represent the string without the terminator, then subtract one from the end iterator of the array, which explains the subtraction in the previous paragraph.
If you don't have an array, but only a pointer - the begin iterator - you can get the end iterator by advancing the beginning by the length of the string. This advancement is a constant operation, because pointers are random access iterators. If you don't know the length, you can call std::strlen to find out (which isn't a constant operation).
Example, std::sort accepts a range of iterators. You can sort a C string like this:
char str[] = "Hello World!";
std::sort(std::begin(str), std::end(str) - 1);
for(char c : "test"); // range-for-loops work as well, but this includes NUL
In the case you don't know the length of the string:
char *str = get_me_some_string();
std::sort(str, str + std::strlen(str));
Specifically, I am interested in a forward iterator
A pointer is a random access iterator. All random access iterators are also forward iterators. A pointer meets all of the requirements listed in the linked iterator concept.
It is possible to write such iterator, something like this should work:
struct csforward_iterator :
std::iterator<std::bidirectional_iterator_tag, const char, void> {
csforward_iterator( pointer ptr = nullptr ) : p( ptr ) {}
csforward_iterator& operator++() { ++p; return *this; }
csforward_iterator operator++(int) { auto t = *this; ++p; return t; }
csforward_iterator& operator--() { --p; return *this; }
csforward_iterator operator--(int) { auto t = *this; --p; return t; }
bool operator==( csforward_iterator o ) {
return p == o.p or ( p ? not ( o.p or *p ) : not *o.p );
}
bool operator!=( csforward_iterator o ) { return not operator==( o ); }
void swap( csforward_iterator &o ) { std::swap( p, o.p ); }
reference operator*() const { return *p; }
pointer operator->() const { return p; }
private:
pointer p;
};
live example
though unfortunately standard one is not provided and it probably would be template over char type (like std::string ).
I'm afraid not, for last you'll need a pointer to the end of the string for which you'll need to call strlen.
If you have a string literal, you can get the end iterator without using std::strlen. If you have only a char*, you'll have to write your own iterator class or rely on std::strlen to get the end iterator.
Demonstrative code for string literals:
#include <iostream>
#include <utility>
template <typename T, size_t N>
std::pair<T*, T*> array_iterators(T (&a)[N]) { return std::make_pair(&a[0], &a[0]+N); }
int main()
{
auto iterators = array_iterators("This is a string.");
// The second of the iterators points one character past the terminating
// null character. To iterate over the characters of the string, we need to
// stop at the terminating null character.
for ( auto it = iterators.first; it != iterators.second-1; ++it )
{
std::cout << *it << std::endl;
}
}
For ultimate safety and flexibility, you end up wrapping the iterator, and it has to carry some state.
Issues include:
random access - which can be addressed in a wrapped pointer by limiting its overloads to block random access, or by making it strlen() on need
multiple iterators - when comparing with each other, not end
decrementing end - which you could again "fix" by limiting the overloads
begin() and end() need to be same type - in c++11 and some api calls.
a non-const iterator could add or remove content
Note that it is "not the iterator's problem" if it is randomly seeked outside the range of the container, and it can legally seek past a string_view.end(). It is also fairly standard that such a broken iterator could not then increment to end() any more.
The most painful of these conditions is that end can be decremented, or subtracted, and dereferenced (usually you can't, but for string it is a null character). This means the end object needs a flag that it is the end, and the address of the start, so that it can find the actual end using strlen() if either of these operations occurs.
Is there a standard C++ iterator class for those cases, or a standard way of doing it without having to copy the string
Iterators are a generalization of pointers. Specifically, they're designed so that pointers are valid iterators.
Note the pointer specializations of std::iterator_traits.
I know I can use a pointer as an iterator, but I would have to know where the string ends
Unless you have some other way to know where the string ends, calling strlen is the best you can do. If there were a magic iterator wrapper, it would also have to call strlen.
Sorry, an iterator is something that is normally obtained from an iterable instance. As char * is a basic type and not a class anymore. How do you think something like .begin() or .end(), can be achieved.
By the way, if you need to iterate a char *p knowing it is nul terminated. you just can do the following.
for( char *p = your_string; *p; ++p ) {
...
}
but the thing is that you cannot use iterators as they are defined in C++, because char * is a basic type, has no constructor, has no destructor or methods associated.

c++ std Copying a list to map

Consider the following:
struct A
{
int i;
double d;
std::string s;
};
std::list<A> list_A;
I'd like to copy all the elements of list_A to a map such that every pair in the map will consist of an element from list_A as value and its string s as key. Is there a way of doing it that is more elegant than looping through the list and insert each element along with its string as key to the map?
I love standard library algorithms and lambdas but it doesn't get much simpler than:
for (const A& value : list_A) {
map_A.insert(std::make_pair(value.s, value));
}
The other methods are doing the equivalent of this code and this loop is readable and just as fast.
This should get you the idea of how to use transform:
std::pair<std::string, A> pairify(const A& a) { return std::make_pair(a.s, a); }
std::transform(list.begin(), list.end(), std::inserter(map, map.end()), pairify);
The reason to use the inserter is:
An insert interator is a special type of output iterator designed to allow algorithms that usually overwrite elements (such as copy) to instead insert new elements automatically at a specific position in the container.
Sorry answered too quickly last time without details, here is a compilable code.
struct A
{
int i;
double d;
std::string s;
};
std::list<A> list_A;
std::pair<std::string, A> convert(const A &x) {
return make_pair(x.s,x);
}
int main() {
std::map<std::string,A> out;
std::transform(list_A.begin(), list_A.end(), std::inserter(out,out.end()),convert);
}
I may store it in a set: in this way there would not be data duplication in the map (s itself):
struct A
{
bool operator < (const A& r_) const { return (s < r_.s); }
int i;
double d;
std::string s;
};
std::list<A> list_A;
std::set<A> set_A;
for ( std::list<A>::const_iterator itr = list_A.begin(); itr != list_A.end(); ++itr ) {
if ( ! set_A.insert(*itr).second ) {
// Handle duplicated elements
}
}
I may keep the loop: in this way you could handle duplicated elements correctly.
If you use C++11 you can use lambda function with capture:
std::map<std::string, A> m;
std::list<A> l;
std::for_each(l.begin(), l.end(),
[&](const A& a) {
m.insert(std::make_pair(a.s, a));
});

Implementing a split() function

Accelerated C++, exercise 14.5 involves reimplementing a split function (which turns text input into a vector of strings). One must use store input in a std::string - like class (Str) & use the split function to return a Vec<Str>, Vec being a std::vector - like container. The Str class manages a custom pointer (Ptr) to the underlying Vec<char> data.
The Str class provides a constructor Str(i,j), in Str.h below, which constructs a Ptr to the underlying Vec
The problem arises when I try to create substrings by calling str(i,j)
I've detailed in the code where the the issues arise.
Here is a whittled-down version of the Str class (can post more code if needed):
Str.h
#include "Ptr.h"
#include "Vec.h"
class Str {
friend std::istream& operator>>(std::istream&, Str&);
public:
// define iterators
typedef char* iterator;
typedef char* const_iterator;
iterator begin() { return data->begin(); }
const_iterator begin() const { return data->begin(); }
iterator end() { return data->end(); }
const_iterator end() const { return data->end(); }
//** This is where we define a constructor for `Ptr`s to substrings **
template<class In> Str(In i, In j): data(new Vec<char>) {
std::copy(i, j, std::back_inserter(*data));
}
private:
// store a Ptr to a Vec
Ptr< Vec<char> > data;
};
Split.h
Vec<Str> split(const Str& str) {
typedef Str::const_iterator iter;
Vec<Str> ret;
iter i = str.begin();
while (i != str.end()) {
// ignore leading blanks
i = find_if(i, str.end(), not_space);
// find end of next word
iter j = find_if(i, str.end(), space);
// copy the characters in `[i,' `j)'
if (i != str.end())
ret.push_back(**substring**); // Need to create substrings here
// call to str(i,j) gives error, detailed below
i = j;
}
return ret;
}
My first thought was to use this constructor to create (pointers to) the required substrings. Calling str(i,j) here gives the error message
type 'const Str' does not provide a call operator
It appears as if one cannot simply call str(i,j) here. Why not?
Could a solution be to write a Str member function which is similar to substr?