std::endl是一个函数模板,其签名为:
template
std::basic_ostream
std::basic_ostream::operator<<重载了std::basic_ostream
当您执行std::cout << std::endl时,会在std::endl上执行重载决议,以确定std::endl的正确模板类型并实例化函数。然后该函数衰减为一个指针,并传递给operator<<。
std::basic_ostream::operator<<然后在相应的ostream上调用该函数,并返回返回值。类似于:
template
std::basic_ostream
std::basic_ostream
std::basic_ostream
) {
return func(*this);
}
但具体实现由编译器库的编写者决定1。
std::endl会导致换行并告诉ostream进行刷新。您可以通过以下两行代码模拟执行 std::cout << std::endl;:
std::cout.put(std::cout.widen('\n'));
std::cout.flush();
std::endl的具体实现取决于编译器,但上述内容是你可能会写的一个不错的近似(当然是在通用流上)。
如果你包含了 #include
std::endl被称为“io操纵符”。该技术旨在允许通过链接在一起的<<调用,在输出命令中设置操作io流状态的函数。
要创建自己的io操纵符,如果您希望它与单个类型的ostream一起使用,则只需创建一个通过引用获取该类型的ostream的函数,并通过引用返回它。 这样就成为了一个io操纵符。
如果您想处理一组流,请创建一个类似于:template
std::basic_ostream
{
return os << os.widen('b') << os.widen('o') << os.widen('b');
}
现在它是一个IO操纵器,可以打印"bob"。它可以对相关的basic_ostream执行任何你想要的操作。
另一个计划是这样的:
struct bob_t {
template
OS& operator()(OS& os)const {
return os << os.widen('b') << os.widen('o') << os.widen('b');
}
template
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
然后,我们可以将 f:(A->A) 的整个重载集合传递给 <<,让“下一层”解决重载。