4

我们知道这endl是操纵器,它在内部放入'\n'缓冲区,然后刷新缓冲区。在哪里endl定义?什么是endl宏或函数或变量或类或对象?如何定义自己的endl操纵器?

cout << "hello" << endl ; /*what is endl and  where it is defined */
4

2 回答 2

18

std::endl是签名的函数模板:

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

std::basic_ostream::operator<<重载std::basic_ostream<CharT,Traits>>::operator<<(std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&))接受某个签名的函数。

当您这样做时,将std::cout << std::endl在 上完成重载决议std::endl,这将确定正确的模板类型std::endl并实例化一个函数。然后它衰减成一个指针,并传递给operator<<.

std::basic_ostream::operator<<然后调用相关 ostream 上的函数,并返回返回值。就像是:

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);
}

但确切的实现取决于编译器库编写器1

std::endl导致打印一个换行符,然后告诉 ostream 刷新自己。std::cout << std::endl;您可以通过这两行代码来模拟:

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

究竟如何std::endl实现取决于编译器,但上面是您如何编写它的一个不错的近似值(自然是在通用流上)。

std::endl如果您#include <ostream>. 如果您包含std库中的任何其他头文件,您可能可以访问它。什么文件准确定义它又取决于实现。

std::endl被称为“io 操纵器”。该技术旨在通过将<<调用链接在一起,允许将操作 io 流状态的函数设置为与输出命令“内联”。

要创建自己的,如果您希望它与单一类型的 ostream 一起工作,只需创建一个函数,该函数通过引用获取该类型ostream,并通过引用返回它。它现在是一个 io 操纵器。

如果要处理一组流,请创建一个模板,如:

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');
}

现在是一个打印"bob". 它可以对问题做任何你想做的事情basic_ostream

另一种方案是这样的:

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;

wherebob现在是一个可以用作 io 操纵器的对象。


1<<重载是类型的函数A->(A->A)->A。基本上,我们不是将 X 传递给 f,而是将 X 和 f 传递给<<,然后传递f(X)。纯语法糖。

作为模板的事实std::endl意味着由于这种技术,完美转发它有点痛苦。我最终定义endl_t了带有operator basic_ostream<CharT,Traits>&(*)(basic_ostream<CharT,Traits>&)()const重载的无状态函数类型,因此有时我可以通过完美的转发代理传递重载集。

然后我们可以传递整个重载集f:(A->A)to <<,并让“下一层”解决重载。

于 2015-11-05T19:33:14.880 回答
4

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

在标题中定义<ostream>

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

如果我想编写自己的 endl 操纵器,我必须编写什么代码?

如果您只想创建它只是为了std::ostream创建一个接受引用std::ostream并返回一个的函数。如果你想让它通用,你可以把它模板化,比如std::endl.

于 2015-11-05T19:29:28.200 回答