ostream, istream, and String^

  • Thread starter Thread starter Peteroid
  • Start date Start date
P

Peteroid

These don't work (I'm using VS C++.NET 2005 Express with clr:/pure syntax):

ostream& operator <<( ostream& output, String^ str )
{
output << str ; //compile error
return output ;
}


istream& operator >>( istream& input, String^ str )
{
input >> str ; // compile error
return input ;
}

What is the correct syntax?

[==P==]
 
I switched this entirely to the new syntax, so this is the question now:

ostream% operator <<( ostream% output, String^ str )
{
output << str ; //compile error
return output ;
}


istream% operator >>( istream% input, String^ str )
{
input >> str ; // compile error
return input ;
}


Thanks for responses!

[==P==]
 
Peteroid said:
I switched this entirely to the new syntax, so this is the question now:

ostream% operator <<( ostream% output, String^ str )
{
output << str ; //compile error
return output ;
}


istream% operator >>( istream% input, String^ str )
{
input >> str ; // compile error
return input ;
}
Would you care to explain which error you see? I don't see anything wrong
with the above syntax. I don't know what you're trying to achive, but the
implementation looks quite pointless. Unless ADL finds an overload with
the same signature in another namespace (in which case the operators
will be ambigious), the implementations recursively call themselves.

You'll probably want something along the lines of
ostream% operator<<( ostream% output, String^ str)
{
pin_ptr<const unsigned char> s =
&System::Text::Encoding::ASCII->GetBytes( str )[0];

return
output << static_cast<const char*>(static_cast<const void*>(s));
}

The second signature does not make sense. Strings are immutable. You
won't get anything. The signature should look like

istream% operator >>( istream% input, String^% str )
{
std::string s;
input >> s;
str = gcnew String( s.c_str() );
}

-hg
 
Would you care to explain which error you see?

The ones I indicated, both of which are something like 'no overload of '<<'
or '>>' exists for String^".

Let me expalin it to you with code that does work. This code does work:

This takes the output stream given as a parameter, uses ITS '<<' operator
for 'int' and adds 'value' to the stream, and then returns the resulting
stream. This is the standard way of doing streaming, such as when saving
values serially to a file.

The '<<' used in the implementation of the method is not the same '<<' this
method defines.

So my problem is because String^ does not have a natural overload of '<<'
which is used to add it to streams. THAT is what I need, is a way to
send/recieve String^'s through a stream (both directions). I'm guessing part
of the problem is that String^ are both variable in length and mutable...

[==P==]


Holger Grund said:
Peteroid said:
I switched this entirely to the new syntax, so this is the question now:

ostream% operator <<( ostream% output, String^ str )
{
output << str ; //compile error
return output ;
}


istream% operator >>( istream% input, String^ str )
{
input >> str ; // compile error
return input ;
}
Would you care to explain which error you see? I don't see anything wrong
with the above syntax. I don't know what you're trying to achive, but the
implementation looks quite pointless. Unless ADL finds an overload with
the same signature in another namespace (in which case the operators
will be ambigious), the implementations recursively call themselves.

You'll probably want something along the lines of
ostream% operator<<( ostream% output, String^ str)
{
pin_ptr<const unsigned char> s =
&System::Text::Encoding::ASCII->GetBytes( str )[0];

return
output << static_cast<const char*>(static_cast<const void*>(s));
}

The second signature does not make sense. Strings are immutable. You
won't get anything. The signature should look like

istream% operator >>( istream% input, String^% str )
{
std::string s;
input >> s;
str = gcnew String( s.c_str() );
}

-hg
 
Peteroid said:
I switched this entirely to the new syntax, so this is the question now:

ostream% operator <<( ostream% output, String^ str )

I'm just curious... How can you use standard C++ library classes, such
as ostream, from a /clr:pure app? /clr:pure means you can't write
unmanaged code. I think you have to use /clr:mixed. But even then,
ostream% looks strange to me, how do you use a managed reference to an
unmanaged type like ostream? Or are you using the yet-to-be-released
STL.NET's ostream? It certainly can't be std::ostream can it? I'm confused.

Tom
 
Peteroid said:
The ones I indicated, both of which are something like 'no overload of
'<<' or '>>' exists for String^".
That doesn't make sense. The operators you have provided are both matches.
Please do post the full error message (am I really the only one who reads
and understands compiler diagnostics *sigh*)
Let me expalin it to you with code that does work. This code does work:
I don't even see how this would compile. Given you have included
iostream there's
std::basic_ostream<..>& std::basic_ostream<..>::operator <<( int )

The above "output << value" should therefore be ambigious. If
ostream is incomplete, the above call would be recursive. Anyway,
your implementation does not add any real value.
This takes the output stream given as a parameter, uses ITS '<<' operator
for 'int' and adds 'value' to the stream, and then returns the resulting
stream. This is the standard way of doing streaming, such as when saving
values serially to a file.
That's not quite correct.
output << value
looks for both member and non-member operators. Non-members in associated
namespaces (std for the above example) are considered. Therefore the
expression
is ambigious.

Can you give a full compilable example?
The '<<' used in the implementation of the method is not the same '<<'
this method defines.
I fail to see how overload resolution could find a better match.
So my problem is because String^ does not have a natural overload of '<<'
which is used to add it to streams. THAT is what I need, is a way to
send/recieve String^'s through a stream (both directions). I'm guessing
part of the problem is that String^ are both variable in length and
mutable...
I've showed you to overloads that should work (I'm not quite sure about the
encoding and conversion, .NET Strings are Unicode while ostream is a
8-bit encoding)

BTW: .NET Strings are immutable. Therefore you should really use a reference
to a handle (String^%)

-hg
 
It's more likely I'M confused (and almost certainly ignorant)... : )

I'm trying to write/read booleans, Strings, int's, etc. to/from a file. I
was just emulating what worked before (iostreams) and so far it does
compile. I assumed if it compiled it was correct (since it does recognize
'ostream%' and 'istream%'). But I haven't tried to save or load to any files
yet with it, so can't say it works. But it does compile!.

Here is some more code that at least compiles (these are part of a bigger
class, but note they are static methods):

#include <fstream>
using std::ifstream ;
using std::ofstream ;

static ostream% Save_Bool( ostream% output, bool value )
{
output << (value) ? int(1) : int(0) ;
return output ;
}

static bool Load_Bool( istream% input )
{
int value ;
input >> value ;
return (value == 1) ;
}

So I guess I should really be asking, since I'm programming using VS C++.NET
2005 Express in clr:/pure syntax (at least so far), what is new the way to
read and write to files since you say its not with streams?

[==P==]
 
Please do post the full error message (am I really the only one who reads
and understands compiler diagnostics *sigh*)

Oh please great kind sir, that is, he who for whom it has been written is
"the only one who reads and understands compiler diagnostics" make of this,
thy requested full error message:

c:\documents and settings\peter\my documents\visual studio
2005\projects\my_project\my_project\my_class.h(1333) : error C2088: '<<' :
illegal for class

for which error C2088 is described as:

"The operator was not defined for the structure or union. This error is only
valid for C code."

For which I assume it means it can't handle String^ since its not 'old
school'. But note it will handle 'int's in precisely this way (or at least
it will compile, even in clr:/pure). Thus the reason for my starting this
thread, basically asking how do I load/save a String^ to/from a file.

Now Tom in another part of this thread has indicated the problem is more
that 'stream's are no longer the way to talk to files. THAT then is what I
really need to know: how DO I read/write to files nowadays? : )

[==P==]
 
I think what I "didn't know I was suppose to be looking for" is the
FileStream class.

Anybody want to tell me why this should have been obvious? That is, how I
was suppose to know such a class existed or what it's name is, or that the
old method no longer works when it compiles for most datatypes? : )

BTW, how did I find about about FileStream's existence? Well, after being
clued in on its existence, the info can be found on MSDN2, but I found it
there using Google!

[==P==]

Peteroid said:
It's more likely I'M confused (and almost certainly ignorant)... : )

I'm trying to write/read booleans, Strings, int's, etc. to/from a file. I
was just emulating what worked before (iostreams) and so far it does
compile. I assumed if it compiled it was correct (since it does recognize
'ostream%' and 'istream%'). But I haven't tried to save or load to any
files yet with it, so can't say it works. But it does compile!.

Here is some more code that at least compiles (these are part of a bigger
class, but note they are static methods):

#include <fstream>
using std::ifstream ;
using std::ofstream ;

static ostream% Save_Bool( ostream% output, bool value )
{
output << (value) ? int(1) : int(0) ;
return output ;
}

static bool Load_Bool( istream% input )
{
int value ;
input >> value ;
return (value == 1) ;
}

So I guess I should really be asking, since I'm programming using VS
C++.NET 2005 Express in clr:/pure syntax (at least so far), what is new
the way to read and write to files since you say its not with streams?

[==P==]

Tamas Demjen said:
I'm just curious... How can you use standard C++ library classes, such as
ostream, from a /clr:pure app? /clr:pure means you can't write unmanaged
code. I think you have to use /clr:mixed. But even then, ostream% looks
strange to me, how do you use a managed reference to an unmanaged type
like ostream? Or are you using the yet-to-be-released STL.NET's ostream?
It certainly can't be std::ostream can it? I'm confused.

Tom
 
Peteroid said:
c:\documents and settings\peter\my documents\visual studio
2005\projects\my_project\my_project\my_class.h(1333) : error C2088: '<<' :
illegal for class

for which error C2088 is described as:

"The operator was not defined for the structure or union. This error is
only valid for C code."
Okay, I must admit the diagnostic is not quite great :-O. Anyway, it means
you apply an operator to a managed class type, for which no overload
is available.
For which I assume it means it can't handle String^ since its not 'old
school'. But note it will handle 'int's in precisely this way (or at least
it will compile, even in clr:/pure). Thus the reason for my starting this
thread, basically asking how do I load/save a String^ to/from a file.
No. There is already an overload which takes an int. You don't have to
code it yourself. I guess the operator<< and operator>> are hidden
by other overloads.

Ok, here's complete compilable code which works perfectly for me.
#include <iostream>
#include <string>

using namespace std;
using namespace System;

namespace System {

ostream% operator <<( ostream% output, String^ str ) {
pin_ptr<const unsigned char> const p =
&System::Text::Encoding::ASCII->GetBytes( str )[0];
return output << static_cast<const char*>( static_cast<const void*>(p));
}

istream% operator >>( istream% input, String^% str ) {
std::string s;
input >> s ;
str = gcnew String( s.c_str() );
return input;
}
} // namespace System

int main() {
String^ s = "Foo";
std::cout << s << std::endl;
System::Console::WriteLine(s);
return 0;
}
Now Tom in another part of this thread has indicated the problem is more
that 'stream's are no longer the way to talk to files. THAT then is what I
really need to know: how DO I read/write to files nowadays? : )
If you want to move to verifiable code (/clr:safe) it is a good idea to
remove
the dependency on the unmanaged CRT and use the .NET classes.

-hg
 
Peteroid said:
I think what I "didn't know I was suppose to be looking for" is the
FileStream class.

Anybody want to tell me why this should have been obvious? That is, how I
was suppose to know such a class existed or what it's name is,
or that the old method no longer works when it compiles for most
datatypes? : )

Well, how did you learn about iostreams a few years ago? I believe that at
least the knowledge aquiring process for the developper hasn't changed much
with avance of the managed .NET world ;-)

Arnaud
MVP - VC
 
Ah, yes, true. But, here's the interesting irony. When I looked for the old
method using classes based on 'iostream' I didn't know of any method, so I
looked till I found one (and it was the correct one). But this time I
already knew a method, so I didn't look for any newer one. Hence, this is a
case where what you do know can hurt you! : )

That being said, I'm now getting pretty good using the StreamWriter and
StreamReader classes, which I like a WHOLE lot better thn 'iostream'
methods. The syntax seems cleaner and more intuitive...

[==P==]
 
Peter said:
Ah, yes, true. But, here's the interesting irony. When I looked for the old
method using classes based on 'iostream' I didn't know of any method, so I
looked till I found one (and it was the correct one). But this time I
already knew a method, so I didn't look for any newer one. Hence, this is a
case where what you do know can hurt you! : )

That being said, I'm now getting pretty good using the StreamWriter and
StreamReader classes, which I like a WHOLE lot better thn 'iostream'
methods. The syntax seems cleaner and more intuitive...
[snip]

Speaking personally, it has taken me many years to disentangle the
back-end of my application from the clutches of CString, CFile and
CWhatever, and I am going to be very resistant to letting the same thing
happen with .NET.

My back-end (which also does the serialization) uses 8-bit strings with
UTF-8, while the Windows part of my app uses "Unicode" (UTF-16). So
every time I pass a string betwen the back and front end I convert it.
So I guess I will do the same with System::String. That way I will never
have to consider mixing iostreams with System::String.

But for now I am still sitting on the .NET fence ....

David Wilkinson

====================
 
Back
Top