By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,103 Members | 1,100 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,103 IT Pros & Developers. It's quick & easy.

Template specialization of an operator

P: n/a
Hi, I am having a bit of trouble with a specialization of operator<<.
Here goes:

class MyStream
{
};
template <typename T>
MyStream& operator<<(MyStream& lhs, T const &)
{
cout << "operator<< T" << endl;
return lhs;
}

// specialize to work differently for std::string
template <> MyStream& operator<<(MyStream& lhs, string const &)
{
cout << "operator<< const string&" << endl;
return lhs;
}

// specialize to work differently for char const*
template <> MyStream& operator<<(MyStream& lhs, char const * const &)
{
cout << "operator<< char const*" << endl;
return lhs;
}

int main()
{
MyStream strm;
int i = 19;
string mystr = "hello";
strm << "hi" << i << mystr << "\n";
return 0;
}

This outputs:
operator<< T
operator<< T
operator<< const string&
operator<< T

Why doesn't strm << "hi" (and << "\n") use the specialized version?
Now I tried changing the operator to these:

template <typename T>
MyStream& operator<<(MyStream& lhs, T)
{
cout << "operator<< T" << endl;
return lhs;
}

// specialize to work differently for std::string
template <> MyStream& operator<<(MyStream& lhs, string const &)
{
cout << "operator<< const string&" << endl;
return lhs;
}

// specialize to work differently for char const*
template <> MyStream& operator<<(MyStream& lhs, char const *)
{
cout << "operator<< char const*" << endl;
return lhs;
}

And the output is:
operator<< char const*
operator<< char const*
operator<< T
operator<< char const*

Now why doesn't strm << mystr use the specialized one? It looks like
it's a perfect match for mystr (not even using a specialization for
string& works).

Can anyone tell me why this happens, and if there is a way to make this
work for both char const* and string const& ?

Thanks a lot,
George Faraj

Jul 31 '05 #1
Share this Question
Share on Google+
6 Replies


P: n/a
YUY0x7 wrote:
Hi, I am having a bit of trouble with a specialization of operator<<.
Here goes:

class MyStream
{
};
template <typename T>
MyStream& operator<<(MyStream& lhs, T const &)
{
cout << "operator<< T" << endl;
return lhs;
}

// specialize to work differently for std::string
template <> MyStream& operator<<(MyStream& lhs, string const &)
{
cout << "operator<< const string&" << endl;
return lhs;
}

// specialize to work differently for char const*
template <> MyStream& operator<<(MyStream& lhs, char const * const &)
{
cout << "operator<< char const*" << endl;
return lhs;
}

int main()
{
MyStream strm;
int i = 19;
string mystr = "hello";
strm << "hi" << i << mystr << "\n";
return 0;
}

This outputs:
operator<< T
operator<< T
operator<< const string&
operator<< T

Why doesn't strm << "hi" (and << "\n") use the specialized version?
Now I tried changing the operator to these:

template <typename T>
MyStream& operator<<(MyStream& lhs, T)
{
cout << "operator<< T" << endl;
return lhs;
}

// specialize to work differently for std::string
template <> MyStream& operator<<(MyStream& lhs, string const &)
{
cout << "operator<< const string&" << endl;
return lhs;
}

// specialize to work differently for char const*
template <> MyStream& operator<<(MyStream& lhs, char const *)
{
cout << "operator<< char const*" << endl;
return lhs;
}

And the output is:
operator<< char const*
operator<< char const*
operator<< T
operator<< char const*

Now why doesn't strm << mystr use the specialized one? It looks like
it's a perfect match for mystr (not even using a specialization for
string& works).

Can anyone tell me why this happens, and if there is a way to make this
work for both char const* and string const& ?

Thanks a lot,
George Faraj


The following mods to your program produces:

operator<< char const*
operator<< T
operator<< const string&
operator<< char const*

Note the changes to the placement of the 'const' keyword
in the various templates and the addition of a template for
pointer args.

// ----------------------
#include <iostream>
#include <string>

using namespace std;

class MyStream
{
};

// default operator<<() for 'const T&' arg
template <typename T>
MyStream& operator<<(MyStream& lhs, const T&)
{
cout << "operator<< T" << endl;
return lhs;
}

// default operator<<() for 'const T *' arg
template <typename T>
MyStream& operator<<(MyStream& lhs, const T *)
{
cout << "operator<< T" << endl;
return lhs;
}

// specialize to work differently for 'const string&'
template <> MyStream& operator<<(MyStream& lhs, const string&)
{
cout << "operator<< const string&" << endl;
return lhs;
}

// specialize to work differently for 'const char *'
template <> MyStream& operator<<(MyStream& lhs, const char *)
{
cout << "operator<< char const*" << endl;
return lhs;
}

int main()
{
MyStream strm;
int i = 19;
string mystr = "hello";
strm << "hi" << i << mystr << "\n";
return 0;
}

Regards,
Larry
Jul 31 '05 #2

P: n/a
Ah, interesting. That helps a lot, thank you very much...

Jul 31 '05 #3

P: n/a

YUY0x7 wrote:
Hi, I am having a bit of trouble with a specialization of operator<<.
Here goes:

class MyStream
{
};
template <typename T>
MyStream& operator<<(MyStream& lhs, T const &)
{
cout << "operator<< T" << endl;
return lhs;
}

// specialize to work differently for std::string
template <> MyStream& operator<<(MyStream& lhs, string const &)
{
cout << "operator<< const string&" << endl;
return lhs;
}

// specialize to work differently for char const*
template <> MyStream& operator<<(MyStream& lhs, char const * const &)
{
cout << "operator<< char const*" << endl;
return lhs;
}

int main()
{
MyStream strm;
int i = 19;
string mystr = "hello";
strm << "hi" << i << mystr << "\n";
return 0;
}

This outputs:
operator<< T
operator<< T
operator<< const string&
operator<< T

Why doesn't strm << "hi" (and << "\n") use the specialized version?
Now I tried changing the operator to these:

template <typename T>
MyStream& operator<<(MyStream& lhs, T)
{
cout << "operator<< T" << endl;
return lhs;
}

// specialize to work differently for std::string
template <> MyStream& operator<<(MyStream& lhs, string const &)
{
cout << "operator<< const string&" << endl;
return lhs;
}

// specialize to work differently for char const*
template <> MyStream& operator<<(MyStream& lhs, char const *)
{
cout << "operator<< char const*" << endl;
return lhs;
}

And the output is:
operator<< char const*
operator<< char const*
operator<< T
operator<< char const*

Now why doesn't strm << mystr use the specialized one? It looks like
it's a perfect match for mystr (not even using a specialization for
string& works).

Can anyone tell me why this happens, and if there is a way to make this
work for both char const* and string const& ?


String literals have type char const[]. To fix the code you may want to
replace your char const* overload with this one:

template <unsigned n>
MyStream& operator<<(MyStream& lhs, char const(&arr)[n])
{
cout << "operator<< char const*" << endl;
return lhs;
}

Jul 31 '05 #4

P: n/a
* YUY0x7:

class MyStream
{
};
template <typename T>
MyStream& operator<<(MyStream& lhs, T const &)
{
cout << "operator<< T" << endl;
return lhs;
}

// specialize to work differently for std::string
template <> MyStream& operator<<(MyStream& lhs, string const &)
{
cout << "operator<< const string&" << endl;
return lhs;
}

// specialize to work differently for char const*
template <> MyStream& operator<<(MyStream& lhs, char const * const &)
{
cout << "operator<< char const*" << endl;
return lhs;
}

int main()
{
MyStream strm;
int i = 19;
string mystr = "hello";
strm << "hi" << i << mystr << "\n";
return 0;
}

This outputs:
operator<< T
operator<< T
operator<< const string&
operator<< T

Why doesn't strm << "hi" (and << "\n") use the specialized version?
First off, Larry Smith's comment about placement of 'const', that you should
"note" it, is misleading:

the placement of 'const' has nothing to do with it.

As Maxim Yegorushkin wrote, a character literal has type 'char const[N]',
which means that while the generic template matches exactly, your 'char
const*' version requires a type conversion, namely decay to pointer. The
compiler chooses the exact match in preference to the conversion. Also as
Maxim wrote you can fix your code by introducing an array argument template,
which I'd do as follows, reusing the existing code (no changes to it):

template< size_t size >
MyStream& operator<<(MyStream& lhs, char const (&s)[size] )
{
return operator<<( lhs, &s[0] );
}

Your 'char const*' function kicks in when you supply an actual pointer as
argument.

The forwarder above kicks in when you supply a character array as argument,
such as a character string literal.

Now I tried changing the operator to these:

template <typename T>
MyStream& operator<<(MyStream& lhs, T)
{
cout << "operator<< T" << endl;
return lhs;
}

// specialize to work differently for std::string
template <> MyStream& operator<<(MyStream& lhs, string const &)
{
cout << "operator<< const string&" << endl;
return lhs;
}

// specialize to work differently for char const*
template <> MyStream& operator<<(MyStream& lhs, char const *)
{
cout << "operator<< char const*" << endl;
return lhs;
}

And the output is:
operator<< char const*
operator<< char const*
operator<< T
operator<< char const*

Now why doesn't strm << mystr use the specialized one? It looks like
it's a perfect match for mystr (not even using a specialization for
string& works).
This one is more difficult and I'm not sure of the answer. I hadn't viewed
a conversion to reference as a type conversion, but perhaps that's what's
needed to understand this: to view string -> string& as a type conversion.
A counter argument is that the actual function call arg is already of type
string& because it's an lvalue, not (only) an rvalue.

Anyway, the string -> string& as conversion view "works" wrt. to the various
outcomes when removing the & for the string specialization, and when adding
a const& for the generic version.

Someone better versed in the details of the standard regarding this issue
can probably explain why string -> string& apparently counts as conversion
in this case (I could probably do it by taking the time, but, enough! ;-)).

Can anyone tell me why this happens,
See above.

and if there is a way to make this
work for both char const* and string const& ?


See above.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 31 '05 #5

P: n/a
Thanks Maxim and Alf...
First off, Larry Smith's comment about placement of 'const', that you should
"note" it, is misleading:


Hah, I didn't even notice that comment made by Larry. I know that the
placement of 'const' had nothing to do with it. I always like to put it
on the left because it makes it clearer what the 'const' is modifying.

Anyways, Larry's solution worked, but the one proposed later by Maxim
and Alf looks more appropriate (shorter too).

Thanks to you three for responding.

Aug 1 '05 #6

P: n/a
Damn... I put 'const' on the right, sorry.

Aug 1 '05 #7

This discussion thread is closed

Replies have been disabled for this discussion.