Better way to use istream to read an ascii value into a char.

J

Jim Langston

In one of my files I am outputting the value of a char into a human readable
file. That is,
char a = 123;
std::eek:fstream CharFile( ("Players\\" + Name + ".char").c_str());
if ( CharFile.is_open() )
CharFile << (int) a;

So the file has the character a stored as "123".

That was the easy part, now comes the fun of reading it back into the char.

I tried a number of things and finally wound up doing this:

std::istream& operator >>( std::istream& is, char& Byte )
{
int temp;
is >> temp;
Byte = temp;
return is;
}

char a;
std::ifstream CharFile( ( "Players\\" + CharName + ".char" ).c_str());
if ( CharFile.is_open() )
CharFile >> a;

You may wonder why I did that instead of just directly reading it into a
temp int directly and assigning, the reason being I'm writing many of these
to the file.

is >> CChar.GM >> CChar.GMLevel >> CChar.Banned >> CChar.Jailed >>
CChar.Muted >>
CChar.MessageRange >> CChar.Avatar >> CChar.Map >> CChar.Pos.x >>
CChar.Pos.y >>
CChar.Pos.z >> CChar.X_Degrees >> CChar.Race >> CChar.Vigor >>
CChar.Fortitude >>
CChar.Coordination >> CChar.Agility >> CChar.Reason >> CChar.Perception >>
CChar.Willpower >> CChar.Psychic >> CChar.Charisma >> CChar.Affinity >>
CChar.AffinityAir >> CChar.AffinityWater >> CChar.AffinityFire >>
CChar.AffinityEarth >> CChar.Sin;

If I had to break this up into different calls it would be, in my opionion,
harder to maintain.

The thing I don't like about overriding the operator >> for a char, though,
is if I ever want to actually write a char as a byte itself (which I don't
think I will).

I'm just wondering if there is a better way.

I attempted something along the lines of:

std::istream& ReadByteVal( std::istream& is, char& Byte ) {/**/}

and then attempted to use it like

is >> ReadByteVal( is, CChar.Agility ) >> ReadByteVal( is, CChar.Reason ) >>
/**/

but that wouldn't compile, the compiler complaining something about not
finding a call taking an rvalue.

Someone else came up with a horrible looking template that seems to be prone
to errors itself. Anyone have any ideas?
 
J

Jonathan Mcdougall

Jim said:
In one of my files I am outputting the value of a char into a human readable
file. That is,
char a = 123;
std::eek:fstream CharFile( ("Players\\" + Name + ".char").c_str());
if ( CharFile.is_open() )
CharFile << (int) a;

So the file has the character a stored as "123".

That was the easy part, now comes the fun of reading it back into the char.

I tried a number of things and finally wound up doing this:

std::istream& operator >>( std::istream& is, char& Byte )
{
int temp;
is >> temp;
Byte = temp;
return is;
}

char a;
std::ifstream CharFile( ( "Players\\" + CharName + ".char" ).c_str());
if ( CharFile.is_open() )
CharFile >> a;

You may wonder why I did that instead of just directly reading it into a
temp int directly and assigning, the reason being I'm writing many of these
to the file.

is >> CChar.GM >> CChar.GMLevel >> CChar.Banned >> CChar.Jailed >>
CChar.Muted >>
CChar.MessageRange >> CChar.Avatar >> CChar.Map >> CChar.Pos.x >>
CChar.Pos.y >>
CChar.Pos.z >> CChar.X_Degrees >> CChar.Race >> CChar.Vigor >>
CChar.Fortitude >>
CChar.Coordination >> CChar.Agility >> CChar.Reason >> CChar.Perception >>
CChar.Willpower >> CChar.Psychic >> CChar.Charisma >> CChar.Affinity >>
CChar.AffinityAir >> CChar.AffinityWater >> CChar.AffinityFire >>
CChar.AffinityEarth >> CChar.Sin;

If I had to break this up into different calls it would be, in my opionion,
harder to maintain.

The thing I don't like about overriding the operator >> for a char, though,
is if I ever want to actually write a char as a byte itself (which I don't
think I will).

I'm just wondering if there is a better way.

I attempted something along the lines of:

std::istream& ReadByteVal( std::istream& is, char& Byte ) {/**/}

and then attempted to use it like

is >> ReadByteVal( is, CChar.Agility ) >> ReadByteVal( is, CChar.Reason ) >>
/**/

but that wouldn't compile, the compiler complaining something about not
finding a call taking an rvalue.

Someone else came up with a horrible looking template that seems to be prone
to errors itself. Anyone have any ideas?

Any easy way would be to make your own stream:

class my_stream
{
public:
my_stream(const std::string& fn)
: ifs_(fn.c_str())
{
}

char read_byte()
{
int i = 0;
ifs_ >> i;
char c = i;
return c;
}

private:
std::ifstream ifs_;
};

my_stream& operator>>(my_stream& s, char& c)
{
c = s.read_byte();
return s;
}

int main()
{
my_stream s("test");
char c;
s >> c;
}

Deriving from std::*istream or aggregating one depends on your design.


Jonathan
 
M

Markus Schoder

Jim said:
In one of my files I am outputting the value of a char into a human readable
file. That is,
char a = 123;
std::eek:fstream CharFile( ("Players\\" + Name + ".char").c_str());
if ( CharFile.is_open() )
CharFile << (int) a;

So the file has the character a stored as "123".

That was the easy part, now comes the fun of reading it back into the char.

I tried a number of things and finally wound up doing this:

std::istream& operator >>( std::istream& is, char& Byte )
{
int temp;
is >> temp;
Byte = temp;
return is;
}

char a;
std::ifstream CharFile( ( "Players\\" + CharName + ".char" ).c_str());
if ( CharFile.is_open() )
CharFile >> a;
[snip]

The thing I don't like about overriding the operator >> for a char, though,
is if I ever want to actually write a char as a byte itself (which I don't
think I will).

I'm just wondering if there is a better way.

I attempted something along the lines of:

std::istream& ReadByteVal( std::istream& is, char& Byte ) {/**/}

and then attempted to use it like

is >> ReadByteVal( is, CChar.Agility ) >> ReadByteVal( is, CChar.Reason ) >>
/**/

but that wouldn't compile, the compiler complaining something about not
finding a call taking an rvalue.

Someone else came up with a horrible looking template that seems to be prone
to errors itself. Anyone have any ideas?

Wrap a char reference in a user defined type and define operator>> for
this type:

#include <iostream>

struct achar
{
achar(char &c) : c_(c) {}
char &c_;
};

std::istream &
operator>>(std::istream &is, achar a)
{
int tmp;
is >> tmp;
a.c_ = tmp;
return is;
}

int
main()
{
char c;
std::cin >> achar(c);
std::cout << c << std::endl;
}
 
J

Jim Langston

Markus Schoder said:
Jim said:
In one of my files I am outputting the value of a char into a human
readable
file. That is,
char a = 123;
std::eek:fstream CharFile( ("Players\\" + Name + ".char").c_str());
if ( CharFile.is_open() )
CharFile << (int) a;

So the file has the character a stored as "123".

That was the easy part, now comes the fun of reading it back into the
char.

I tried a number of things and finally wound up doing this:

std::istream& operator >>( std::istream& is, char& Byte )
{
int temp;
is >> temp;
Byte = temp;
return is;
}

char a;
std::ifstream CharFile( ( "Players\\" + CharName + ".char" ).c_str());
if ( CharFile.is_open() )
CharFile >> a;
[snip]

The thing I don't like about overriding the operator >> for a char,
though,
is if I ever want to actually write a char as a byte itself (which I
don't
think I will).

I'm just wondering if there is a better way.

Wrap a char reference in a user defined type and define operator>> for
this type:

#include <iostream>

struct achar
{
achar(char &c) : c_(c) {}
char &c_;
};

std::istream &
operator>>(std::istream &is, achar a)
{
int tmp;
is >> tmp;
a.c_ = tmp;
return is;
}

int
main()
{
char c;
std::cin >> achar(c);
std::cout << c << std::endl;
}

Ahh, perfect, thanks! I'm sure you meant
std::istream &
operator>>(std::istream &is, achar& a)
 
J

Jim Langston

Jim Langston said:
Ahh, perfect, thanks! I'm sure you meant
std::istream &
operator>>(std::istream &is, achar& a)

I guess I was wrong on this. I tried it with the achar& a and the compiler
warned about converting an achar a to an achar& a on a non constant
variable. So I put it the way you had it and it seems to work (compiled,
only one warning about achar not being able to have an assigment oporator
generated) but not tested. Thanks again.
 
J

Jonathan Mcdougall

Jim said:
I guess I was wrong on this.

Note that achar takes the char by reference, not by value. So whether
achar itself is passed by value or reference does not matter.
I tried it with the achar& a and the compiler
warned about converting an achar a to an achar& a on a non constant
variable.

In the statement

std::cin >> achar(c);

"achar(c)" constructs an rvalue which cannot be bound to a non-const
reference. You must either pass it by value or by const reference.


Jonathan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top