我想重载(劫持?)ostream
和basic_ostream<unsigned char>
,以便它停止尝试将八位字节(unsigned char)显示为可打印字符。
我一直和cout
生活在一起,朋友们在屏幕上放笑脸的时间太长了。而且我已经厌倦了与演员一起工作:hex << int(0xFF & b) << ...
。
是否可以覆盖标准行为?我已经尝试过模板和非模板覆盖。他们编译,但似乎没有被调用。
答案 0 :(得分:5)
问题是已经存在
template<class charT, class traits>
std::basic_ostream<charT,traits>&
operator<<(std::basic_ostream<charT,traits>&, charT);
namespace std
中的。由于basic_ostream<>
也在此命名空间中,因此当您输出unsigned char
时,ADL会将其选中。添加自己的重载可能会使调用操作符不明确,或者会无声地忽略您的重载。
但即使它会起作用,也会很脆弱,因为忘记一个包含可能会在没有编译器诊断的情况下巧妙地改变代码的含义。
还有更多:每个维护程序员看这样的代码都会假设调用标准运算符(并且在向代码添加另一个输出语句时从不考虑添加include)。
简而言之, 最好添加一个功能 做你想做的事情。
一种合理的语义替代方法可能是添加一个调用所需输出格式的流操纵器。不过,我不确定这在技术上是否可行。
答案 1 :(得分:4)
Luc是对的。
您当前方法的更快替代方案 - 如果您不介意十进制输出 - 是将char提升为int
:
unsigned char c = '!';
os << +c;
我不知道这会怎么征税!
答案 2 :(得分:3)
#include <iostream>
#include <string> // std::char_traits
typedef unsigned char UChar;
typedef UChar Byte;
typedef std::char_traits<char> CharTraits;
typedef std::char_traits<wchar_t> WCharTraits;
typedef std::basic_ostream< char, CharTraits > CharOStream;
typedef std::basic_ostream< wchar_t, WCharTraits > WCharOStream;
CharOStream& operator<<( CharOStream& stream, UChar v )
{
return stream << v+0;
}
int main()
{
char const c = 'c';
UChar const u = 'u';
std::cout << c << '\n' << u << std::endl;
}
这适用于MSVC 10.0和MinGW g ++ 4.4.1,并且它与Comeau Online完全编译,所以我相信它是正式的。
干杯&amp;第h。,
答案 3 :(得分:3)
Als是对的,你所要求的不会发生。
您可以做的最好的事情是write your own IO manipulator (iomanip
) to do the magic for you.在这种情况下,您需要一个unsigned char
的功能(尽管我强烈建议使用uint8_t
来自<stdint.h>
)。
#include <stdint.h>
#include <ostream>
class asHex
{
public:
asHex(uint8_t theByte): value(theByte) {}
void operator()(std::ostream &out) const
{ std::ios::fmtflags oldFlags = out.flags; out << std::hex
<< std::setw(2) << std::setfill('0') << std::uppercase << theByte;
out.flags(oldFlags); }
private:
uint8_t theByte;
};
std::ostream& operator<<(std::ostream &out, asHex number)
{
number(out); return out;
}
然后你可以写:
cout << asHex(myByte);
您可以向asHex
添加构造函数,甚至可以将其作为模板类来支持16,32和其他位数。
(是的,我知道<stdint.h>
不是官方的C ++标题,但我宁愿在全局命名空间而不是std::
中定义它,而不必执行using namespace std;
在全局命名空间中转储所有。)
答案 4 :(得分:1)
由于ADL,将调用标准operator<<
。尝试明确限定您的电话:
::operator<<(os, 42);
答案 5 :(得分:1)
您无法直接覆盖std::cout
的行为。如果任何dev代码可以改变其他代码使用的标准库的行为,那将太容易出错。
您可以创建自己的类,模仿std::cout
的行为并改为使用该对象。
class SpecialCout
{
template <typename T>
friend SpecialCout& operator<< ( SpecialCout const& scout, T const &t )
{
// Do any adjustments to t here, or decide to return early.
std::cout << t;
return *this;
}
};
extern SpecialCout scout;