Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where is endl manipulator defined

Tags:

c++

gcc

endl

We know that endl is manipulator and internally it put '\n' to buffer and then flush up the buffer. Where is endl defined? What is endl, is it macro or function or variable or class or object? How can I define my own endl manipulator?

cout << "hello" << endl ; /*what is endl and  where it is defined */
like image 745
Niravsinh Parmar Avatar asked Nov 29 '22 10:11

Niravsinh Parmar


2 Answers

std::endl is a function template of signature:

template<class CharT, class Traits>
std::basic_ostream<CharT,Traits>& endl(std::basic_ostream<CharT,Traits>&);

The std::basic_ostream::operator<< overload std::basic_ostream<CharT,Traits>>::operator<<(std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&)) accepts a function of a certain signature.

When you do std::cout << std::endl, overload resolution is done on std::endl, which determines the proper template types for std::endl and instantiates a function. This then decays into a pointer, and is passed to operator<<.

std::basic_ostream::operator<< then calls the function on the ostream in question, and returns the return value. Something like:

template<class CharT, class Traits>
std::basic_ostream<CharT, Traits>&
std::basic_ostream<CharT, Traits>::operator<<(
  std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&)
) {
  return func(*this);
}

But the exact implementation is up to the compiler library writer1.

std::endl causes a newline to be printed, and then tells the ostream to flush itself. You can emulate doing std::cout << std::endl; via these two lines of code:

std::cout.put(std::cout.widen('\n'));
std::cout.flush();

How exactly std::endl is implemented is up to the compiler, but the above is a decent approximation of how you might write it (naturally on a generic stream).

You are guaranteed to have access to std::endl if you #include <ostream>. You may have access to it if you include any other header file from the std library. What file exactly defines it is again up to the implementation.

std::endl is known as an "io manipulator". This technique is intended to allow functions that manipulate the io stream's state to be set up "inline" with output commands by chaining << calls together.

To create your own, if you want it to work with a single type of ostream, simply create a function that takes that kind of ostream by reference, and returns it by reference. It is now an io manipulator.

If you want to handle a set of streams, create a template like:

template<class CharT, class Traits>
std::basic_ostream<CharT, Traits>& bob(std::basic_ostream<CharT, Traits>& os)
{
  return os << os.widen('b') << os.widen('o') << os.widen('b');
}

which is now an io manipulator that prints "bob". It can do whatever you want to the basic_ostream in question.

An alternative plan is this:

struct bob_t {
  template<class OS>
  OS& operator()(OS& os)const {
    return os << os.widen('b') << os.widen('o') << os.widen('b');
  }
  template<class OS>
  operator OS&(*)(OS&)() const {
    return [](OS& os)->OS&{ return bob_t{}(os); };
  }
};
static const bob_t bob;

where bob is now an object that can be used as an io manipulator.


1 This << overload is a function of type A->(A->A)->A. Basically, instead of passing X to f, we pass X and f to <<, which then does f(X). Pure syntactic sugar.

The fact that std::endl is a template means that perfect forwarding it is a bit of a pain due to this technique. I end up defining stateless function endl_t types, with an operator basic_ostream<CharT,Traits>&(*)(basic_ostream<CharT,Traits>&)()const overload, so I can pass the overload set through perfect forwarding proxies sometimes.

Then we can pass the entire overload set of f:(A->A) to <<, and have the "next layer down" resolve the overload.

like image 60
Yakk - Adam Nevraumont Avatar answered Dec 02 '22 00:12

Yakk - Adam Nevraumont


http://en.cppreference.com/w/cpp/io/manip/endl says:

Defined in header <ostream>

template< class CharT, class Traits >
std::basic_ostream<CharT, Traits>& endl( std::basic_ostream<CharT, Traits>& os );

if i want to code my own endl manipulator what code i will have to write?

If you want to create it only for std::ostream just create a function that accepts reference to std::ostream and returns one. If you want to make it generic you can make it templatized, like std::endl.

like image 23
Slava Avatar answered Dec 01 '22 22:12

Slava