Without the using
, it is clear: the compiler will not find any
of the member overloads of <<
, because your function hides
them. The <<
is a member, so without the using
, it
disappears. The <<
is not a member, so it still works.
When you add the using
: all of the member overloads are
visible, as if they were members of your class. And
"string"
will be converted to a char const*
. The overload
that the compiler is trying to resolve is:
operator<<( mystream<char>, char const* ).
Now consider some of the overloads to be considered:
std::ostream& mystream::operator<<( void const* );
std::ostream& mystream::operator<<( bool );
std::ostream& operator<<( std::ostream&, char const* );
For the first argument (foo
, a mystream
), the first two
functions are both better matches than the third (since they are
an exact match); for the second argument (the string literal),
the third function is a better match. Thus: ambiguous.
More generally, there are several problems with your code.
Fundamentally, you do not add <<
operators by deriving. As
you see, it doesn't work. Perhaps more significantly, something
like:
foo << 123 << m;
will not work, because foo << 123
returns a std::ostream&
,
not a mystream
, and there is no <<
which will work with an
std::ostream&
and a modifier
. You add <<
operators by
defining new free functions:
std::ostream&
operator<<( std::ostream& dest, modifier const& other )
{
// ...
return *this;
}
If you need additional data to format, you use xalloc
and
iword
or pword
to get it, e.g. to define a manipulator:
static int Modifier::modIndex = std::ostream::xalloc();
class mod1
{
int myModifier;
public:
mod1( int m ) : myModifier( m ) {}
friend std::ostream& operator<<( std::ostream& dest,
mod1 const& mod )
{
dest.iword( modIndex ) = myModifier;
return *this;
}
};
You then access dest.iword( modIndex )
to get this information
in the output routine.
iword()
returns a long&
, different for each instance of your
stream (and for each different index you use).
If you need more information, you can use pword
instead of
iword
—pword
returns a reference to a void*
. If you
want use it to point to dynamically allocated memory, don't
forget to register a callback to delete it (using
ios_base::register_callback
).