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

anything wrong with conversion operator?

P: n/a
Consider:

#include <string>
#include <iostream>
using namespace std;

struct S
{
const char* ps_;
operator string();
};

int main()
{
S s;
cout << s;
}

operator<<(ostream&, const string&) is defined in the standard and
the conversion from S to string is, too. But compilers reject this code
since operator<<(ostream&, const S&) is not defined.
What's wrong with this code?

--
ES Kim
Jul 22 '05 #1
Share this Question
Share on Google+
14 Replies


P: n/a
* ES Kim:
Consider:

#include <string>
#include <iostream>
using namespace std;

struct S
{
const char* ps_;
operator string();
};

int main()
{
S s;
cout << s;
}

operator<<(ostream&, const string&) is defined in the standard and
the conversion from S to string is, too.
The Holy Standard says nothing about your struct S.

But compilers reject this code
As they should.

since operator<<(ostream&, const S&) is not defined.
If you're sure that's the reason...

What's wrong with this code?


.... then why are you asking this?

Is this homework?

Anyway, even with the code corrected (always post code that is complete,
if possible) MSVC 7.1 rejects it. It has no problem with conversion
to 'char const*', however. I don't know why, but one slight difference is
that in the MSVC implementation of the standard library the operator<< for
strings must infer template arguments such as the allocator type for the
string; why that should matter just baffles me, since both operator
implementations must infer template arguments for the stream.
--
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 22 '05 #2

P: n/a
* Alf P. Steinbach:
* ES Kim:
Consider:

#include <string>
#include <iostream>
using namespace std;

struct S
{
const char* ps_;
operator string();
};

int main()
{
S s;
cout << s;
}


Anyway, even with the code corrected (always post code that is complete,
if possible) MSVC 7.1 rejects it. It has no problem with conversion
to 'char const*', however. I don't know why, but one slight difference is
that in the MSVC implementation of the standard library the operator<< for
strings must infer template arguments such as the allocator type for the
string; why that should matter just baffles me, since both operator
implementations must infer template arguments for the stream.


Adding the following to the mix (after class S, for example) works so it
seems to have to do with template argument deduction -- there is a rule
about just direct conversions being tried, but I don't recall exactly:

template<class Traits> inline
basic_ostream<char, Traits>& operator<<(
basic_ostream<char, Traits>& stream,
const basic_string<char>& s
)
{
return std::operator<<( stream, s );
}

--
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 22 '05 #3

P: n/a
"Alf P. Steinbach" <al***@start.no> wrote in message
news:41****************@news.individual.net...
... code snipped
operator<<(ostream&, const string&) is defined in the standard and
the conversion from S to string is, too.
The Holy Standard says nothing about your struct S.

But compilers reject this code


As they should.

since operator<<(ostream&, const S&) is not defined.


If you're sure that's the reason...

What's wrong with this code?


... then why are you asking this?

Is this homework?


I wish it were. I'm too old to do such a thing. ;-)

Anyway, even with the code corrected (always post code that is complete,
if possible) MSVC 7.1 rejects it. It has no problem with conversion
to 'char const*', however. I don't know why,
Neither do I, and that's why I asked the question.
Ok, let me clarify.

struct S
{
operator const char*();
};

S s;
cout << s;

If you define S like this, it's fine, and operator<<(ostream&, const char*)
is called. Why not with operator string()?
but one slight difference is
that in the MSVC implementation of the standard library the operator<< for
strings must infer template arguments such as the allocator type for the
string; why that should matter just baffles me, since both operator
implementations must infer template arguments for the stream.


The original code is rejected not just with MSVC but also with gcc and comeau.
So I think it's not just an implementation problem but language-related one.
--
ES Kim
Jul 22 '05 #4

P: n/a
"Alf P. Steinbach" <al***@start.no> wrote in message
news:41*****************@news.individual.net...
* Alf P. Steinbach:
* ES Kim:
... code snipped
Anyway, even with the code corrected (always post code that is complete,
if possible) MSVC 7.1 rejects it. It has no problem with conversion
to 'char const*', however. I don't know why, but one slight difference is
that in the MSVC implementation of the standard library the operator<< for
strings must infer template arguments such as the allocator type for the
string; why that should matter just baffles me, since both operator
implementations must infer template arguments for the stream.


Adding the following to the mix (after class S, for example) works so it
seems to have to do with template argument deduction -- there is a rule
about just direct conversions being tried, but I don't recall exactly:

template<class Traits> inline
basic_ostream<char, Traits>& operator<<(
basic_ostream<char, Traits>& stream,
const basic_string<char>& s
)
{
return std::operator<<( stream, s );
}


Well, I don't think this is a solution. If this code and std::string-related
headers are included in a same source somehow, it will cause an ambiguity.

--
ES Kim
Jul 22 '05 #5

P: n/a
* ES Kim:

template<class Traits> inline
basic_ostream<char, Traits>& operator<<(
basic_ostream<char, Traits>& stream,
const basic_string<char>& s
)
{
return std::operator<<( stream, s );
}


Well, I don't think this is a solution. If this code and std::string-related
headers are included in a same source somehow, it will cause an ambiguity.


Well it doesn't with MSVC 7.1. And I don't think with any other compiler
either. It's a better match -- but perhaps one should take a look at
what operator<<'s the standard specifies (I'm too lazy to do that).
--
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 22 '05 #6

P: n/a
"Alf P. Steinbach" <al***@start.no> wrote in message
news:41*****************@news.individual.net...
* ES Kim:

template<class Traits> inline
basic_ostream<char, Traits>& operator<<(
basic_ostream<char, Traits>& stream,
const basic_string<char>& s
)
{
return std::operator<<( stream, s );
}
Well, I don't think this is a solution. If this code and std::string-related headers are included in a same source somehow, it will cause an ambiguity.


Well it doesn't with MSVC 7.1. And I don't think with any other compiler
either.


Hmmm... that's strange. It does with gcc and comeau, not just with MSVC.
Here's my test code:

#include <iostream>
#include <string>

struct S
{
char* s;
operator string();
};

// your code
template<class Traits> inline
basic_ostream<char, Traits>& operator<<(
basic_ostream<char, Traits>& stream,
const basic_string<char>& s
)
{
return std::operator<<( stream, s );
}

int main()
{
S s;
std::cout << s;
std::string str;
std::cout << str; // ambiguous
}
It's a better match -- but perhaps one should take a look at
what operator<<'s the standard specifies (I'm too lazy to do that).


This is from the standard:

template<class charT, class traits, class Allocator>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& os,
const basic_string<charT, traits, Allocator>& str);

Does your code match better than this one? I'm not sure.

--
ES Kim
Jul 22 '05 #7

P: n/a
* ES Kim:
"Alf P. Steinbach" <al***@start.no> wrote in message
news:41*****************@news.individual.net...
* ES Kim:
>
> template<class Traits> inline
> basic_ostream<char, Traits>& operator<<(
> basic_ostream<char, Traits>& stream,
> const basic_string<char>& s
> )
> {
> return std::operator<<( stream, s );
> }

Well, I don't think this is a solution. If this code and std::string-related headers are included in a same source somehow, it will cause an ambiguity.


Well it doesn't with MSVC 7.1. And I don't think with any other compiler
either.


Hmmm... that's strange. It does with gcc and comeau, not just with MSVC.
Here's my test code:

#include <iostream>
#include <string>

struct S
{
char* s;
operator string();
};

// your code
template<class Traits> inline
basic_ostream<char, Traits>& operator<<(
basic_ostream<char, Traits>& stream,
const basic_string<char>& s
)
{
return std::operator<<( stream, s );
}

int main()
{
S s;
std::cout << s;
std::string str;
std::cout << str; // ambiguous
}


Ooops.

It's a better match -- but perhaps one should take a look at
what operator<<'s the standard specifies (I'm too lazy to do that).


This is from the standard:

template<class charT, class traits, class Allocator>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& os,
const basic_string<charT, traits, Allocator>& str);

Does your code match better than this one? I'm not sure.


I'm not sure either.

In such situations I apply the simple rule: don't rely on things that
are hard to understand or generally unknown.

So a 'toString' member function in class S is one solution (although it
would be nice to know the answer(s) to this question, also).

--
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 22 '05 #8

P: n/a
"Alf P. Steinbach" <al***@start.no> wrote in message
news:41*****************@news.individual.net...

So a 'toString' member function in class S is one solution (although it
would be nice to know the answer(s) to this question, also).


Yes, this is what I would do in real code. Someone asked the question
and I was just curious. No, not exactly. I'm dying to know the answer. :-)

--
ES Kim
Jul 22 '05 #9

P: n/a
ES Kim wrote:
Consider:

#include <string>
#include <iostream>
using namespace std;

struct S
{
const char* ps_;
operator string();
};

int main()
{
S s;
cout << s;
}

operator<<(ostream&, const string&) is defined in the standard and
the conversion from S to string is, too. But compilers reject this code
since operator<<(ostream&, const S&) is not defined.
What's wrong with this code?

The most serious error here is that you use operator definition for fun.
operator definitions can cause unexpected/hidden errors, so must be used
with extreme caution.
#include <string>
#include <iostream>

struct S
{
const char *ps_;
};
inline
std::ostream &operator<<(std::ostream &o, const S &s)
{
return std::cout<<s.ps_;
}

int main()
{
S s = {0};
std::cout << s;
}

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #10

P: n/a
Ioannis Vranos wrote:

The most serious error here is that you use operator definition for fun.
operator definitions can cause unexpected/hidden errors, so must be used
with extreme caution.

I was talking about operator Type() definitions. Avoid them.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #11

P: n/a
"Ioannis Vranos" <iv*@guesswh.at.grad.com> wrote in message
news:cj***********@ulysses.noc.ntua.gr...
Ioannis Vranos wrote:

The most serious error here is that you use operator definition for fun.
operator definitions can cause unexpected/hidden errors, so must be used
with extreme caution.

I was talking about operator Type() definitions. Avoid them.


Yes, I know why the conversion operator must be used with caution
and agree on that. But I'm not talking about the recommended style.
What I'm asking is "Why the original code is rejected even if the
conversion is defined?" It's about syntax.

--
ES Kim
Jul 22 '05 #12

P: n/a
ES Kim posted:
Consider:

#include <string>
#include <iostream>
using namespace std;

struct S
{
const char* ps_;
operator string();
};

int main()
{
S s;
cout << s;
}

operator<<(ostream&, const string&) is defined in the standard and
the conversion from S to string is, too. But compilers reject this code
since operator<<(ostream&, const S&) is not defined.
What's wrong with this code?

int main()
{
k = 7;
}
That's one problem in anyway.
-JKop
Jul 22 '05 #13

P: n/a
"ES Kim" <no@spam.mail> wrote in message news:<cj**********@news1.kornet.net>...
Consider:

#include <string>
#include <iostream>
using namespace std;

struct S
{
const char* ps_;
operator string();
};

int main()
{
S s;
cout << s;
}

operator<<(ostream&, const string&) is defined in the standard and
the conversion from S to string is, too. But compilers reject this code
since operator<<(ostream&, const S&) is not defined.
What's wrong with this code?


With the code:
cout << s;
Why would the compiler look for an << operator in std::string?
It can't go looking into every possible conversion type for obvious reasons.

Paul.
Jul 22 '05 #14

P: n/a
ES Kim wrote in news:cj**********@news1.kornet.net in comp.lang.c++:
Consider:

#include <string>
#include <iostream>
using namespace std;

struct S
{
const char* ps_;
operator string();
};

int main()
{
S s;
cout << s;
}

operator<<(ostream&, const string&) is defined in the standard and
the conversion from S to string is, too. But compilers reject this code
since operator<<(ostream&, const S&) is not defined.
What's wrong with this code?


std::string is a typedef for std::basic_string< char > and operator <<
in std is a template and its second argument is involved in TAD (template
argument deduction), such template arguments must be exact matches.

The only (*) conversion's allowed (or possible if you like) are derived
to base conversion's, User defined convertion's (operator Type()
and converting constructors) aren't considered as they can play no
role in TAD.

*) All the normal rvalue/lvalue and qualification adjustment can
occur as usual.
An example:

#include <iostream>
#include <ostream>

/* Forward
*/
template < typename T > struct D;

template < typename T > struct A
{
A() {}
A( D< T > const & ) {};
};

template < typename T > struct B : A < T > {};

template < typename T > struct C
{
operator A< T > () const { return A< T >(); }
};

template < typename T > struct D {};
template < typename T >
void f( A< T > )
{
std::cout << "f( A< T > )\n";
}

int main()
{
A< int > a;

f( a );

B< int > b;

f( b );

#if 0
C< int > c;

f( c ); /* Not Ok User defined conversion (operator) */
#endif

#if 0
D< int > d;

f( d ); /* Not Ok User defined conversion (constructor) */
#endif

}

HTH.

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #15

This discussion thread is closed

Replies have been disabled for this discussion.