https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107813
--- Comment #4 from Jonathan Wakely <redi at gcc dot gnu.org> --- (In reply to Grzegorz Drzewiecki from comment #3) > (In reply to Jonathan Wakely from comment #1) > > When you call this->o << t then there is no exact match, so an implicit > > conversion to unsigned char happens. > > OK. But what botter me. I've added global operator like: > > std::ostream &operator<<(std::ostream &os, unsigned char c) { Adding this is undefined behaviour, you're not allowed to redefine what it means to write fundamental types to std::istream. > return os << static_cast<unsigned int>(c); > } > > With this one my example works fine: > > f << cat << " vs " << dog << "\n\r"; > > stdout: 67 vs 68. > > There is different conversion for either global operator or template > operator. No there isn't. You've just changed what the "this->o << t" expression inside the template operator does. That template operator is still called, but now it uses a different function to print the enum. You can easily verify this by stepping through the code in a debugger. There is no GCC bug here, this is just how C++ works.