-2

I have read about I/O manipulators and have thereof been a little confused.It is stated that it is because of these manipulators that we are able to control streams using << and >>. I am not quite sure why, but I have always thought that is was objects, such as std::cout, that controlled the functionality of operators, such as <<.

How is it even possible that functions, since I/O manipulators allegedly are functions, can overload/define operators? :/

Being specific, they state the following for manipulators taking arguments:

These manipulators define their own operator<< or operator>> which perform the requested manipulation.

If this is true - that it is not the objects (the classes that they belong to), but these helper functions that control the operators << and >> - how it is known what to do in the following statement?

std::cout << "static constructor\n";
  • Can someone explain the downvotes? I have tried my best to elaborate on my confusion. Maybe the question is stupid, as I said, I am rather certain that I have misunderstood something, but that is exactly why I have reached out to you guys. –  Nov 16 '17 at 22:52
  • 1
    I didn't vote but it sounds like you have not really done any research into how overloaded operators work at all. I would recommend reading through [this Q/A](https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading) – M.M Nov 16 '17 at 22:59

2 Answers2

1

The standard input and output stream classes (std::basic_istream and std::basic_ostream) overload member and non-member operator>>() and operator<<() functions. Those are the functions that perform the actual I/O. Manipulators are functions like std::endl, std::left, std::right, std::boolalpha, etc. They merely complement the functionality provided by the I/O operator functions. They allow us to control certain properties of the I/O operation like floating point representation, field width, fill characters, and so on.

In regards to the example you provided:

std::cout << "static constructor\n";

This calls the non-member function ostream& operator<<(ostream&, const char*); which does the actual output of the string.

A manipulator can be defined like this:

std::ostream& print_1_to_10( std::ostream& os ) {
  for (int i = 1; i <= 10; i++) {
    os << to_string(i);
  }
}

The standard stream classes have member overloads of operator>>() and operator<<() which take as an argument a pointer to a function with the above signature. Basically it goes like:

std::ostream& std::ostream::operator<<(std::ostream&(*pf)(std::ostream&)) {
  pf(*this);
  return *this;
}

This allows us to do:

std::cout << print_1_to_10;

which is what allows manipulators to work.

So in summary, manipulators are simply helper functions that facilitate certain kinds of operations.


There is also the case where you might want something that resembles a manipulator, but in addition you want to pass arguments to this manipulator (i.e std::cout << print_1_to(10)). In that case it is customary to create a class that contains an overloaded operator<<() or operator>>() depending on what you want to do.

struct print_1_to {
  int n;
  print_1_to(int n) : n(n) {}
  friend std::ostream& operator<<(std::ostream& os, print_1_to const& p) {
    for (int i = 1; i <= p.n; i++) {
      os << to_string(i);
    }
    return os;
  }
};
David G
  • 94,763
  • 41
  • 167
  • 253
  • That's a good answer but it's not quite complete. It is how `std::endl` works, but the quoted text in the question applies to "manipulators taking arguments", which use a slightly different mechanism. – rici Nov 17 '17 at 02:45
  • Thank you!! But if it is said that manipulators are functions, how come the struct print_1_to is considered a manipulators? I know that there is a contructor, but it is still an instantiation of a struct. –  Nov 17 '17 at 10:12
  • @sdsadasdasd It's not a manipulator. It's a class that acts like a manipulator. – David G Nov 17 '17 at 15:13
  • @0x499602D2 oh okay! But based on what you said, cppreference's statement "Manipulators are helper functions that make it possible to control input/output streams using operator<< or operator>>." just seems to totally wrong. Isn't that right? –  Nov 18 '17 at 16:33
  • Also, they state "The manipulators that are invoked with arguments (e.g. std::cout << std::setw(10);) are implemented as functions returning objects of unspecified type. These manipulators define their own operator << or operator >> which perform the requested manipulation." - if "These manipulators define their own operator << or operator >> which perform the requested manipulation", aren't they classes that act like a manipulator as the one you wrote in your answer? Otherwise, they would not be able to define their own versions, correct? Thanks! I really appreciate your time. –  Nov 18 '17 at 21:40
  • @noflow Yes, that is correct. They are classes that act as manipulators. A manipulator is a function with the signature `basic_istream& (basic_stream&)` or `basic_ostream& (basic_ostream&)` (which basically means "a function that takes an input stream and returns the given input stream or a function that takes an output stream and returns the given output stream") – David G Nov 19 '17 at 02:27
0

The text you quote is poor wording.

The standard headers define both the manipulator, and a free-function overloaded operator whose operands are the stream and the manipulator. The manipulator does not overload an operator per se.

The manipulator is indeed a function template. It is possible to overload operators so that one of the operands can be a function or a function template. In the latter case, the overloaded operator is itself a function template.

In your last statement, the syntax x << y is transformed to the function call operator<<(x, y); and then the ordinary name lookup and overload resolution process resolves that call in the same way as any other function call.

M.M
  • 138,810
  • 21
  • 208
  • 365