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

发布于 2024-11-29 18:42:20 字数 293 浏览 0 评论 0 原文

我想重载(劫持?)ostreambasic_ostream 以便它停止尝试将八位字节(无符号字符)显示为可打印字符。

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

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

I want to overload (hijack?) ostream and basic_ostream<unsigned char> so that it stops attempting to display an octet (unsigned char) as a printable character.

I've been living with cout and friends putting smiley faces on the screen for far too long. And I'm tired of working around with casts: hex << int(0xFF & b) << ....

Is it possible to override the standard behavior? I've tried both template and non-template overrides. They compile, but do not appear to be called.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

云巢 2024-12-06 18:42:20

问题是

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

命名空间 std 中已经存在一个。由于 basic_ostream<> 也在该命名空间中,因此当您输出 unsigned char 时,ADL 会选取它。添加您自己的重载可能会使调用运算符变得不明确,或者您的重载将被默默地忽略。

但即使它能工作,它也会很脆弱,因为忘记一个包含可能会巧妙地改变代码的含义,而无需编译器进行任何诊断。
还有更多:每个查看此类代码的维护程序员都会假设调用了标准运算符(并且在向代码添加另一个输出语句时永远不会想到添加包含)。
简而言之,最好添加一个函数来完成您想做的事情。

一个合理的语义替代方案可能是添加一个流操纵器来调用您想要的输出格式。不过,我不确定这在技术上是否可行。

The problem is that there already is a

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

in namespace std. Since basic_ostream<> is also in this namespace, ADL picks it up when you output an unsigned char. Adding your own overload might make calling the operator ambiguous, or your overload will silently be ignored.

But even if it would work, it would be brittle, because forgetting one include might subtly alter the meaning of the code without any diagnostic from the compiler.
And there's more: Every maintenance programmer looking at such code will assume the standard operator is called (and never think of adding an include when he adds another output statement to the code).
In short, it might be best to add a function doing what you want to do.

A reasonable semantic alternative to that might be to add a stream manipulator that invokes the output format you want. I'm not sure if that's technically possible, though.

喜爱纠缠 2024-12-06 18:42:20

吕克是对的。

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

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

我不明白这会带来多大的负担!

Luc is correct.

A quicker alternative to your current approach — if you don't mind decimal output — is to promote the char to int:

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

I don't see how this would be taxing!

鹊巢 2024-12-06 18:42:20
#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 干净地编译,所以我相信它在形式上没问题。

干杯&呵呵,

#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;
}

This works nicely with MSVC 10.0 and MinGW g++ 4.4.1, and it compiles cleanly with Comeau Online, so I believe it's formally OK.

Cheers & hth.,

夏尔 2024-12-06 18:42:20

阿尔斯是对的​​,你所要求的事情不会发生。

你能做的最好的事情就是编写你自己的IO操纵器(iomanip)来为你施展魔法。在这种情况下,你需要一个接受unsigned char的函数(尽管我强烈建议使用 中的 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 和其他位数。

(是的,我知道 不是官方的 C++ 头文件,但我宁愿将其定义放在全局命名空间中,而不是 std:: 中必须执行 using namespace std; 转储全局命名空间中的所有内容。)

Als is right that what you're asking for isn't going to happen.

The best you can do is to write your own IO manipulator (iomanip) to do the magic for you. In this case, you need a function that takes an unsigned char (though I'd strongly recommend using uint8_t from <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;
}

Then you can write:

cout << asHex(myByte);

You can add constructors to asHex or even make it a template class to support 16, 32, and other bit counts.

(Yes, I know <stdint.h> is not an official C++ header, but I'd rather have its definitions in the global namespace instead of std:: without having to do a using namespace std; which dumps everything in the global namespace.)

世态炎凉 2024-12-06 18:42:20

由于 ADL,将调用标准operator<<。尝试明确限定您的调用:

::operator<<(os, 42);

Due to ADL the standard operator<< will be called. Try to explicitly qualify your call:

::operator<<(os, 42);
海拔太高太耀眼 2024-12-06 18:42:20

您无法直接覆盖 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;

You cannot override the behavior of std::cout directly. It would be too error-prone if any dev code can change the behavior of the standard library used by other code.

You can create your own class that emulates the behavior of std::cout and use that object instead.

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文