endl操纵器在哪里定义

时间:2015-11-05 19:25:47

标签: c++ gcc endl

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

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

2 个答案:

答案 0 :(得分:14)

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"的io操纵器。它可以为您所需的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;

其中bob现在是一个可以用作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)的整个重载集传递给<<,并让“下一层”解决过载。

答案 1 :(得分:3)

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