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 tri开发者_如何学运维ed both template and non-template overrides. They compile, but do not appear to be called.
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.
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!
#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.,
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.)
Due to ADL the standard operator<<
will be called. Try to explicitly qualify your call:
::operator<<(os, 42);
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;
精彩评论