Leurs définitions -ainsi que tous les types de flux et buffers de la std- se trouvent dans <iosfwd> (pour ios forward, voir le billet précédent ;)). Inutile d'inclure <ostream> ou <istream> et encore moins <iostream>.
Sur le web beaucoup d'exemples se basent uniquement sur std::ostream et std::istream, mais ce ne sont en fait que des alias.
typedef basic_istream<char> istream;
typedef basic_ostream<char> ostream;
Les exemples montrés avec ces 2 types ne fonctionnent pas lorsque par exemple un std::wcout est utilisé (flux de sortie standard de type wostream = basic_ostream<wchar_t>).
Pour un maximum de compatibilité, il faut utiliser les classes de bases, ce qui donne :
#include <iosfwd>
template<typename _CharT, typename _Traits>
std::basic_ostream<_CharT, _Traits>&
operator<<(std::basic_ostream<_CharT, _Traits>& os, const MyType& a)
{
return os << ...;
}
template<typename _CharT, typename _Traits>
std::basic_istream<_CharT, _Traits>&
operator>>(std::basic_istream<_CharT, _Traits>& is, MyType& a)
{
return is >> ...;
}
Dans certaines circonstances, le flux devrait avoir un accès aux membres privés, il faudra donc en faire une fonction amie.
class MyType
{
//...
template<typename _CharT, typename _Traits>
friend std::basic_ostream<_CharT, _Traits>&
operator<<(std::basic_ostream<_CharT, _Traits>& os, const MyType& a);
};