Structure of std::endl [duplicate]
Asked Answered
M

3

6

I am new to C++ and I am confused about std::endl. When trying to understand what std::endl is, I had faced some resources which told me that it is a function.

However, how can a function be deprived of parentheses?

Marmalade answered 21/9, 2017 at 11:20 Comment(2)
There's a difference between a function and a function call.Darcee
A function without parentheses is like an integer without a +, or an aray without a [], or a string without a printf. You pass it around, put it aside, then when its time comes, you retrieve it and stick it in front of a list of arguments. (Technically you are oassing a function pointer or reference around, but this is not important at this moment).Lippmann
W
4

However, how can a function be deprived of parentheses?

The name of a function, without being followed by (), is just a reference to that function. It's exactly the same as with any other type:

void foo(int) {}

char x = 'a';

char *p = &x;

int main()
{
  p;  // Refers to p
  *p; // Dereferences p (refers to whatever p points to)
  foo;  // Refers to foo
  foo(42); // Calls foo
}

std::endl is a function (actually a function template) which takes one parameter of type "a stream", and works by inserting an EOL representation into that stream and then flushing it. You can actually use it like any other function, if you want to:

std::endl(std::cout);

The final piece of the puzzle is that the standard library provides an overload (again, a template) of operator << such that the LHS argument is a stream and the RHS argument is a function; the implementation of this operator calls the RHS argument (the function) and passes it the LHS one (the stream). Conceptually, there's something like this:

Stream& operator<< (Stream &s, const Function &f)
{
  f(s);
  return s;
}

Therefore, calling std::cout << std::endl invokes that operator overload, which in turn invokes std::endl(std::cout), which does the EOL insertion + flushing.

As to which form is to be preferred (direct call vs. << operator), it's definitely the use of <<. It's idiomatic, and it allows easy composition of multiple stream manipulators within a single expression. Like this:

std::cout << "Temperature: " << std::fixed << std::setprecision(3) << temperature << " (rounds to " << std::setprecision(1) << temperature << ')' << std::endl;
Warfare answered 21/9, 2017 at 11:37 Comment(10)
Calling std::cout << std::endl(std::cout) gives an error, or am I doing something wrong?Ruler
@Ruler Try std::endl(std::cout); instead of std::cout << std::endl; as a single statement.Literary
@Ruler you are trying to send return value of std::endl(std::cout) function to stream std::cout, and that's stream reference, so you are doing something like std::cout << std::cout, with intermission of sending also EOL to the stream by the endl function. I.e. doesn't make that much sense.Box
@Literary Ah so this has the same functionality as std::cout << std::endl?Ruler
@Ruler I never spoke about streaming the result of calling std::endl(std::cout) anywhere. Just call it like a plain old function.Warfare
@Ruler Yes, that's what the answer says. Doing std::cout << std::endl is effectively syntactic sugar for calling std::endl(std::cout), which inserts the newline & flushes the stream.Warfare
@Angew Is there a reason to use one above the other? I always learned to do std::cout << std::endl at least.Ruler
@Ruler Of course, std::cout << std::endl is indeed the idiomatic way. I would never write std::endl(std::cout) in real code, since it's unfamiliar. I was just explaining how it works under the hood.Warfare
It should be noted that the reason to use stream manipulators at all is that they can be easily composed with operator <<, e.g. std::cout << "The temperature is " << std::fixed << std::right << std::setw(5) << std::setprecision(2) << temperature << std::endl;; For direct function calls, you'd always need to use multiple statements or operator , to avoid ordering issues.Fritz
@ArneVogel Good point, thanks. I'll incorporate it into the answer when I have the time (probably tomorrow).Warfare
N
6

Read the ref:

std::endl

Inserts a new-line character and flushes the stream.

It's used with a stream, for example std::cout.

It's not a function, it's a function template.

std::endl without parentheses refers to a set of overload functions - all possible specializations of that function template. Read more in How does std::endl not use any brackets if it is a function?

Needlewoman answered 21/9, 2017 at 11:24 Comment(3)
Even being a function template, it is still a function and OP is asking why you dont need to call it as std::endl()Garnes
@Needlewoman you answer's quite fast :)Teneshatenesmus
I saw it at the time of post @ishpreet! =)Needlewoman
W
4

However, how can a function be deprived of parentheses?

The name of a function, without being followed by (), is just a reference to that function. It's exactly the same as with any other type:

void foo(int) {}

char x = 'a';

char *p = &x;

int main()
{
  p;  // Refers to p
  *p; // Dereferences p (refers to whatever p points to)
  foo;  // Refers to foo
  foo(42); // Calls foo
}

std::endl is a function (actually a function template) which takes one parameter of type "a stream", and works by inserting an EOL representation into that stream and then flushing it. You can actually use it like any other function, if you want to:

std::endl(std::cout);

The final piece of the puzzle is that the standard library provides an overload (again, a template) of operator << such that the LHS argument is a stream and the RHS argument is a function; the implementation of this operator calls the RHS argument (the function) and passes it the LHS one (the stream). Conceptually, there's something like this:

Stream& operator<< (Stream &s, const Function &f)
{
  f(s);
  return s;
}

Therefore, calling std::cout << std::endl invokes that operator overload, which in turn invokes std::endl(std::cout), which does the EOL insertion + flushing.

As to which form is to be preferred (direct call vs. << operator), it's definitely the use of <<. It's idiomatic, and it allows easy composition of multiple stream manipulators within a single expression. Like this:

std::cout << "Temperature: " << std::fixed << std::setprecision(3) << temperature << " (rounds to " << std::setprecision(1) << temperature << ')' << std::endl;
Warfare answered 21/9, 2017 at 11:37 Comment(10)
Calling std::cout << std::endl(std::cout) gives an error, or am I doing something wrong?Ruler
@Ruler Try std::endl(std::cout); instead of std::cout << std::endl; as a single statement.Literary
@Ruler you are trying to send return value of std::endl(std::cout) function to stream std::cout, and that's stream reference, so you are doing something like std::cout << std::cout, with intermission of sending also EOL to the stream by the endl function. I.e. doesn't make that much sense.Box
@Literary Ah so this has the same functionality as std::cout << std::endl?Ruler
@Ruler I never spoke about streaming the result of calling std::endl(std::cout) anywhere. Just call it like a plain old function.Warfare
@Ruler Yes, that's what the answer says. Doing std::cout << std::endl is effectively syntactic sugar for calling std::endl(std::cout), which inserts the newline & flushes the stream.Warfare
@Angew Is there a reason to use one above the other? I always learned to do std::cout << std::endl at least.Ruler
@Ruler Of course, std::cout << std::endl is indeed the idiomatic way. I would never write std::endl(std::cout) in real code, since it's unfamiliar. I was just explaining how it works under the hood.Warfare
It should be noted that the reason to use stream manipulators at all is that they can be easily composed with operator <<, e.g. std::cout << "The temperature is " << std::fixed << std::right << std::setw(5) << std::setprecision(2) << temperature << std::endl;; For direct function calls, you'd always need to use multiple statements or operator , to avoid ordering issues.Fritz
@ArneVogel Good point, thanks. I'll incorporate it into the answer when I have the time (probably tomorrow).Warfare
T
0

endl is an output-only I/O manipulator.

endl is an output-only I/O manipulator, it may be called with an expression such as out << std::endl for any out of type std::basic_ostream.

Inserts a newline character into the output sequence os and flushes it as if by calling os.put(os.widen('\n')) followed by os.flush().

Teneshatenesmus answered 21/9, 2017 at 11:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.