我已经读过关于I/O manipulators并且有点混淆。据说这是因为这些操纵器我们能够使用<<和>>。我不太清楚为什么,但我一直认为是控制运算符功能的对象,例如std :: cout,例如<<。
如果I / O操纵器据称是函数,那么函数怎么可能超载/定义运算符呢? :/
具体而言,他们为操纵者提出以下陈述:
这些操纵者定义他们自己的操作符<<或运算符>>哪一个 执行请求的操作。
如果这是真的 - 它不是对象(它们所属的类),而是控制运算符的这些辅助函数<<和>> - 如何知道在下面的陈述中做什么?
std::cout << "static constructor\n";
答案 0 :(得分:1)
标准输入和输出流类(std::basic_istream
和std::basic_ostream
)重载成员和非成员operator>>()
和operator<<()
函数。这些是执行实际I / O的函数。操纵器是std::endl
,std::left
,std::right
,std::boolalpha
等功能。它们只是补充 I / O操作员功能提供的功能。它们允许我们控制I / O操作的某些属性,如浮点表示,字段宽度,填充字符等。
关于您提供的示例:
std::cout << "static constructor\n";
这将调用执行字符串实际输出的非成员函数ostream& operator<<(ostream&, const char*);
。
可以像这样定义一个操纵器:
std::ostream& print_1_to_10( std::ostream& os ) {
for (int i = 1; i <= 10; i++) {
os << to_string(i);
}
}
标准流类具有operator>>()
和operator<<()
的成员重载,它们将指向具有上述签名的函数的指针作为参数。基本上它就像:
std::ostream& std::ostream::operator<<(std::ostream&(*pf)(std::ostream&)) {
pf(*this);
return *this;
}
这允许我们这样做:
std::cout << print_1_to_10;
允许操纵者工作的东西。
总而言之,操纵器只是帮助某些操作的辅助函数。
还有一种情况,你可能想要一些类似于操纵器的东西,但另外你想要将参数传递给这个操纵器(即std::cout << print_1_to(10)
)。在这种情况下,习惯上创建一个包含重载operator<<()
或operator>>()
的类,具体取决于您想要做什么。
struct print_1_to {
int n;
print_1_to(int n) : n(n) {}
friend std::ostream& operator<<(std::ostream& os, print_1_to const& p) {
for (int i = 1; i <= p.n; i++) {
os << to_string(i);
}
return os;
}
};
答案 1 :(得分:0)
你引用的文字是措词不好。
标准头文件定义了操纵器和一个自由函数重载操作符,其操作数是流和操纵器。操纵器不会使操作员本身过载。
操纵器确实是一个功能模板。可以重载运算符,使其中一个操作数可以是函数或函数模板。在后一种情况下,重载运算符本身就是一个函数模板。
在你的上一个语句中,语法x << y
被转换为函数调用operator<<(x, y);
,然后普通名称查找和重载解析过程以与任何其他函数调用相同的方式解析该调用。 / p>