[编辑 - 我很久以前就忘记了这一点,直到我得到2,500个观点“值得注意的问题”。由于人们正在查看 - 在接受的答案中有关于重载的有用信息,但具体检查std::endl
甚至比我当时意识到的更糟糕,而且肯定是错误的。
基本上,std::endl
的效果是将\n
输出到流,然后用std::flush
刷新。这与平台无关,包括Windows终端真的是“\ r \ n”。 endl
操纵器不抽象平台差异WRT行结束,C ++以与C相同的方式处理 - 通过将\n
转换为“\ r \ n”(对于文本模式,而不是二进制)稍后的。我认为C ++正在做一些不同的事情,一个如此强烈的假设我甚至从未质疑它20年,但我错了。
我不记得细节,但无论如何都可以定义自己的流,并提供流式传输的任何字符的替代输出(和翻译)。所有操纵器应按预期工作,之前您的自定义流代码会查看生成的输出字符。因此,要提供特殊的行尾行为,请注意那里的\n
(它仍然在文本文件行结束前的翻译之前)。
]
我知道,它是hackish,但我最近需要实现一个流类,它的行为大部分就像一个标准流,但它会检测std :: endl操纵器和特殊情况下的行为。我对特定方法实现的第一次尝试是......
mystream& mystream::operator<< (std::basic_ostream<char>& (*p) (std::basic_ostream<char>&))
{
if (p == &std::endl)
{
// Handle special case
}
else
{
m_Underlying_Stream << p;
}
return *this;
}
这样做的麻烦在于编译器不知道我指的是哪个std::endl
的重载。我解决了以下问题......
mystream& mystream::operator<< (std::basic_ostream<char>& (*p) (std::basic_ostream<char>&))
{
typedef std::basic_ostream<char>& (*ENDL_T) (std::basic_ostream<char>&);
const ENDL_T l_ENDL (&std::endl);
if (p == l_ENDL)
{
// Handle special case
}
else
{
m_Underlying_Stream << p;
}
return *this;
}
那就是编译器可以在初始化的上下文中解决重载问题(对于赋值也可以解决另一个实验),但不适用于operator==
。
有问题的编译器是MinGW GCC 4.4.0,但我不认为这可能是编译器问题。
我环顾四周,发现了这个问题......
How to get the address of an overloaded member function?
如果我的代码有const问题,我不知道缺少const需要去哪里。我看不到任何其他明显的类型问题。
我对WRT重载或隐式转换的步骤数问题有一些模糊的想法,但没有具体的。所以 - 任何人都可以清楚地解释我的第一个例子有什么问题,为什么第二个版本修复它,以及我如何能够安全地指出我在获取函数地址时的重载。
顺便说一句 - 我猜有些人不会喜欢我直接测试std::endl
的地址,并会指出这是脆弱的 - 例如有人可以拥有自己的操纵者,调用std::endl
我不会发现。总的来说这是事实,但在这种特殊情况下,黑客可以节省大量时间,并且不重要。
答案 0 :(得分:2)
只允许在一组有限的上下文中使用不带参数的重载函数名称(或函数模板的名称,其行为类似于一组重载函数)(例如在“地址”表达式中)其中上下文可用于唯一确定所需的特定过载。
这在标准(ISO / IEC 14882:2003)[over.over]的13.4中规定。包括对象或引用的初始化程序或显式转换。这为您提供了许多选择。
E.g。显式转换:
typedef std::ostream& (*ManipPtr)(std::ostream&);
mystream& mystream::operator<<(ManipPtr p)
{
if (p == static_cast<ManipPtr>(&std::endl))
{
// ...
直接初始化指针:
typedef std::ostream& (*ManipPtr)(std::ostream&);
mystream& mystream::operator<<(ManipPtr p)
{
const ManipPtr pEndl = &std::endl;
if (p == pEndl)
{
// ...
答案 1 :(得分:1)
以下作品:
#include <iostream>
struct mystream {
typedef std::basic_ostream<char>& (*ENDL_T) (std::basic_ostream<char>&);
mystream& operator<< (ENDL_T p)
{
if (p == (ENDL_T)std::endl)
{
std::cout << "special case\n";
}
else
{
std::cout << "usual case\n";
}
return *this;
}
};
int main()
{
mystream ms;
ms << std::endl; // prints "special case"
ms << std::flush; // prints "usual case"
}
答案 2 :(得分:0)
它无法区分重载的原因是因为您正在解析函数的地址,而不是调用它。当您将其插入流中时,编译器知道调用endl(ostream&)
重载。除此之外,你是独自一人。
为什么不直接测试'\ n'?