重载运算符<<(无符号字符类型定义作为字节)

Overload operator<< (unsigned char typedef as byte)

本文关键字:lt 字节 定义 无符号 运算符 重载 字符 类型      更新时间:2023-10-16

我想重载(hijack?)ostreambasic_ostream<unsigned char>,以便它停止尝试将八位字节(无符号字符)显示为可打印字符。

我已经和cout和朋友们一起在屏幕上放笑脸太久了。我已经厌倦了使用强制转换:hex << int(0xFF & b) << ... .

是否有可能覆盖标准行为?我尝试过模板和非模板覆盖。它们可以编译,但似乎没有被调用。

问题是已经有了

template<class charT, class traits>
std::basic_ostream<charT,traits>& 
operator<<(std::basic_ostream<charT,traits>&, charT);

in namespace std。由于basic_ostream<>也在这个名称空间中,因此当您输出unsigned char时,ADL会拾取它。添加您自己的重载可能会使调用操作符具有二义性,或者您的重载将被静默地忽略。

但是即使它能工作,它也是脆弱的,因为忘记一个包含可能会微妙地改变代码的含义,而不需要编译器的任何诊断。
还有更多:每个维护程序员看到这样的代码都会假设调用了标准操作符(当他向代码中添加另一个输出语句时,永远不会想到添加include)。
简而言之,最好添加一个函数来做您想做的事情。

一个合理的语义替代方案可能是添加一个调用所需输出格式的流操纵符。但我不确定这在技术上是否可行。

Luc是正确的。

比当前方法更快的替代方案—如果你不介意十进制输出—是将char提升为int:

unsigned char c = '!';
os << +c;

我看不出这有什么费力的!

#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++ 4.4.1中工作得很好,并且它在Comeau Online中编译得很干净,所以我相信它是正式的。

干杯,hth。

Als是对的,你所要求的不会发生。

你能做的最好的事情就是编写你自己的IO操纵符(iomanip)来为你完成这个魔术。在这种情况下,您需要一个接受unsigned char的函数(尽管我强烈建议从<stdint.h>中使用uint8_t)。

#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;在全局命名空间中转储所有)

由于ADL,标准operator<<将被调用。尝试显式限定调用:

::operator<<(os, 42);

不能直接覆盖std::cout的行为。如果任何开发代码都可以改变其他代码使用的标准库的行为,那将太容易出错。

可以创建您自己的类来模拟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;