Overloading Operators for User-Defined Types (NOT Classes!)

R

Randy

Is there a way to override operators for user-defined types
(e.g., typedefs) rather than class types?

I'm trying to override the extractor operator for a user-defined
enumeration type but getting no joy. For example,

typedef enum {SUN,MON,TUES,WED,THURS,FRI,SAT} WEEK;

istream& operator>> (istream& is, WEEK& x)
{
x = blah blah;
return is;
}



--RY
 
V

Victor Bazarov

Randy said:
Is there a way to override operators for user-defined types
(e.g., typedefs) rather than class types?

'typedefs' are _not_ user-defined types.
I'm trying to override the extractor operator for a user-defined
enumeration type but getting no joy. For example,

typedef enum {SUN,MON,TUES,WED,THURS,FRI,SAT} WEEK;

istream& operator>> (istream& is, WEEK& x)
{
x = blah blah;
return is;
}

FAQ 5.8. Aside from 'blah blah', the code should be fine.

V
 
R

Randy

#include <string>
#include <iostream>
#include <sstream>
using namespace::std
#include <stdint.h>

typedef enum {SUN,MON,TUE,WED,THU,FRI,SAT} WEEK;

#define MAXCHARS_IN_ALINE 256

istream& operator>> (istream& is, WEEK& x)
{
char aline[MAXCHARS_IN_ALINE];

is.getline(aline, MAXCHARS_IN_ALINE;

if (((string)aline).find("SUN", 0) != string::npos)
{
x = SUN;
return is;
}

if (((string)aline).find("MON", 0) != string::npos)
{
x = MON;
return is;
}

if (((string)aline).find("TUE", 0) != string::npos)
{
x = TUE;
return is;
}

if (((string)aline).find("WED", 0) != string::npos)
{
x = WED;
return is;
}

if (((string)aline).find("THU", 0) != string::npos)
{
x = THU;
return is;
}

if (((string)aline).find("FRI", 0) != string::npos)
{
x = FRI;
return is;
}

if (((string)aline).find("SAT", 0) != string::npos)
{
x = SAT;
return is;
}

x = MON;
return is;
}

int main(int argc, char **argv)
{
string strTest;
WEEK week;

strTest = "THU";
istringstream(strTest) >> week;

cout << (uint16_t)week;
return 0;
}

yields the following slurry of errors:

make -f over.mak TARGET=native PLATFORM=linux
DSPROOT_DIR=/home/yates/modetest/
over.mak:101: no file name for `include'
Building Autodependencies (over) for Application over
over.mak:101: no file name for `include'
Building Component (over) for Application over
/home/yates/modetest/host/app/modetest/over.cpp:7: error: expected `;'
before "typedef"
/home/yates/modetest/host/app/modetest/over.cpp: In function
`std::istream& operator>>(std::istream&, WEEK&)':
/home/yates/modetest/host/app/modetest/over.cpp:15: error: expected `)'
before ';' token
/home/yates/modetest/host/app/modetest/over.cpp: In function `int
main(int, char**)':
/home/yates/modetest/host/app/modetest/over.cpp:69: error: no match for
'operator>>' in 'istringstream(((const std::basic_string<char,
std::allocator<char> >&)((const said:
*)(&strTest))), _S_in) >> week'
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:87:
note: candidates are: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT,
_Traits>::eek:perator>>(std::basic_istream<_CharT,
_Traits>&(*)(std::basic_istream<_CharT, _Traits>&)) [with _CharT =
char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:93:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(std::basic_ios<_CharT,
_Traits>&(*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char,
_Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:102:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT,
_Traits>::eek:perator>>(std::ios_base&(*)(std::ios_base&)) [with _CharT =
char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:111:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(bool&) [with _CharT =
char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:133:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(short int&) [with
_CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:164:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(short unsigned int&)
[with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:186:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(int&) [with _CharT =
char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:217:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(unsigned int&) [with
_CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:239:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(long int&) [with _CharT
= char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:261:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(long unsigned int&)
[with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:284:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(long long int&) [with
_CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:306:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(long long unsigned
int&) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:329:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(float&) [with _CharT =
char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:351:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(double&) [with _CharT =
char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:373:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(long double&) [with
_CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:395:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT, _Traits>::eek:perator>>(void*&) [with _CharT =
char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/bits/istream.tcc:417:
note: std::basic_istream<_CharT, _Traits>&
std::basic_istream<_CharT,
_Traits>::eek:perator>>(std::basic_streambuf<_CharT, _Traits>*) [with
_CharT = char, _Traits = std::char_traits<char>]
/home/yates/modetest/host/app/modetest/over.cpp:12: note:
std::istream& operator>>(std::istream&, WEEK&)
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/istream:692:
note: std::basic_istream<char, _Traits>&
std::eek:perator>>(std::basic_istream<char, _Traits>&, signed char*) [with
_Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/istream:687:
note: std::basic_istream<char, _Traits>&
std::eek:perator>>(std::basic_istream<char, _Traits>&, unsigned char*)
[with _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/istream:651:
note: std::basic_istream<char, _Traits>&
std::eek:perator>>(std::basic_istream<char, _Traits>&, signed char&) [with
_Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../include/c++/3.4.3/istream:646:
note: std::basic_istream<char, _Traits>&
std::eek:perator>>(std::basic_istream<char, _Traits>&, unsigned char&)
[with _Traits = std::char_traits<char>]
make: *** [/home/yates/modetest/host/app/modetest/nativelinux/over.o]
Error 1

Compilation exited abnormally with code 2 at Wed Jan 4 16:27:23
 
R

Randy

'typedefs' are _not_ user-defined types.

Why not?!!! They define types that aren't built-in, so they're
user.

--RY
 
J

Jay Nabonne

#include <string>
#include <iostream>
#include <sstream>
using namespace::std

using namespace::std;


The error message says it all (missing ; before typedef):
/home/yates/modetest/host/app/modetest/over.cpp:7: error: expected `;'
before "typedef"

- Jay
 
J

Jay Nabonne

Why not?!!! They define types that aren't built-in, so they're
user.

--RY

Typedefs create aliases for other types. For example:

typedef int BOOL;
typedef char* PCHAR;

I think the confusion came about because you defined an enum and typedef'd
it at the same time.

typedef enum {SUN,MON,TUES,WED,THURS,FRI,SAT} WEEK;

declares an unnamed enum and then creates an alias for it called WEEK. All
you need is:

enum WEEK {SUN,MON,TUES,WED,THURS,FRI,SAT};

to define an enum called WEEK.

- Jay
 
V

Victor Bazarov

Randy said:
#include <string>
#include <iostream>
#include <sstream>
using namespace::std
^^^^^^^^^^^^^^^^^^^^
Semicolon is missing at the end of this line.
#include <stdint.h>

There is no such standard header.
typedef enum {SUN,MON,TUE,WED,THU,FRI,SAT} WEEK;

#define MAXCHARS_IN_ALINE 256

istream& operator>> (istream& is, WEEK& x)
{
char aline[MAXCHARS_IN_ALINE];

is.getline(aline, MAXCHARS_IN_ALINE;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A closing parenthesis is missing in this line
[...]
> istringstream(strTest) >> week;

This is not going to work. A reference to non-const object cannot be
bound to a temporary. You need a named object (not temporary).

After fixing syntax errors and removing "(uint16_t)", your code compiled
and executed fine under VC++ v7.1 and VC++ v8, and MIPSpro 7.4 compilers.
I was unable to test with Comeau online since the server is not responding
but I am sure it would also compile it.

V
 
M

mlimber

Randy said:
Is there a way to override operators for user-defined types
(e.g., typedefs) rather than class types?

I'm trying to override the extractor operator for a user-defined
enumeration type but getting no joy. For example,

typedef enum {SUN,MON,TUES,WED,THURS,FRI,SAT} WEEK;

istream& operator>> (istream& is, WEEK& x)
{
x = blah blah;
return is;
}

You might be interested in this article:

http://www.cuj.com/documents/s=8470/cujboost0306besser/

Cheers! --M
 
R

Randy

Typedefs create aliases for other types. For example:
typedef int BOOL;
typedef char* PCHAR;

OK, so typedef doesn't ALWAYS define a new type. However, it can.
I think the confusion came about because you defined an enum and typedef'd
it at the same time.

typedef enum {SUN,MON,TUES,WED,THURS,FRI,SAT} WEEK;

declares an unnamed enum and then creates an alias for it called WEEK. All
you need is:

enum WEEK {SUN,MON,TUES,WED,THURS,FRI,SAT};

to define an enum called WEEK.

Here you are mistaken. If I replace the typedef with a simple enum, I
get

over.cpp:12: error: `WEEK' is not a type

You need to typedef it if you want to declare variables of that type.

--RY
 
P

Pete Becker

Randy said:
OK, so typedef doesn't ALWAYS define a new type. However, it can.

A typedef never defines a new type. It defines a synonym for an existing
type. Jay's discussion is correct:
Here you are mistaken. If I replace the typedef with a simple enum, I
get

over.cpp:12: error: `WEEK' is not a type

You need to typedef it if you want to declare variables of that type.

No, you don't. But since you didn't include the code for you "simple
enum" it's not possible for anyone to tell what triggered that error
message.
 
R

Randy

Randy said:
^^^^^^^^^^^^^^^^^^^^
Semicolon is missing at the end of this line.

Right. Sorry about that.
There is no such standard header.

Yes there is - see ISO C 99.
typedef enum {SUN,MON,TUE,WED,THU,FRI,SAT} WEEK;
#define MAXCHARS_IN_ALINE 256
istream& operator>> (istream& is, WEEK& x)
{
char aline[MAXCHARS_IN_ALINE];
is.getline(aline, MAXCHARS_IN_ALINE;

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A closing parenthesis is missing in this line

Correct. Sorry again. (I fixed all these after posting - I
didn't realize they were there at first.)
istringstream(strTest) >> week;

This is not going to work. A reference to non-const object cannot be
bound to a temporary. You need a named object (not temporary).

OK, this seems to be the crux of the matter. I found that streaming
from cin works so it's not the overloaded operator.

Bear with me because I don't understand the meaning of your words. What
in "istringstream(strTest) >> week;" is non-const? What do you mean
by "You need a named object (not temporary)."?

After fixing syntax errors and removing "(uint16_t)", your code compiled
and executed fine under VC++ v7.1 and VC++ v8, and MIPSpro 7.4 compilers.
I was unable to test with Comeau online since the server is not responding
but I am sure it would also compile it.

Thanks Victor. How did you fix the non-const blah blah above?

--RY
 
J

Jay Nabonne

Here you are mistaken. If I replace the typedef with a simple enum, I
get

over.cpp:12: error: `WEEK' is not a type

You need to typedef it if you want to declare variables of that type.

In C yes (which is why typedefs were so prevalent). That's no longer
the case in C++. This code compile fine using Visual C++:

enum WEEK {SUN,MON,TUES,WED,THURS,FRI,SAT};

int main()
{
WEEK week = MON;
return 0;
}

- Jay
 
J

Jay Nabonne

OK, so typedef doesn't ALWAYS define a new type. However, it can.

Oops. Missed the first part.

I would love to see a typedef that actually defines a type as opposed
to being an alias for one.

Even in your case, if you name the enum:

typedef enum week_t {SUN,MON,TUES,WED,THURS,FRI,SAT} WEEK;

WEEK is an alias for the enumeration week_t (or, in C, "enum week_t").

- Jay
 
V

Victor Bazarov

Randy said:
Right. Sorry about that.




Yes there is - see ISO C 99.

Then you need to rewrite your program in C 99 and post to comp.lang.c.
C++ Standard only refers to C 90 at this point.
typedef enum {SUN,MON,TUE,WED,THU,FRI,SAT} WEEK;
#define MAXCHARS_IN_ALINE 256
istream& operator>> (istream& is, WEEK& x)
{
char aline[MAXCHARS_IN_ALINE];
is.getline(aline, MAXCHARS_IN_ALINE;

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A closing parenthesis is missing in this line


Correct. Sorry again. (I fixed all these after posting - I
didn't realize they were there at first.)

istringstream(strTest) >> week;

This is not going to work. A reference to non-const object cannot be
bound to a temporary. You need a named object (not temporary).


OK, this seems to be the crux of the matter. I found that streaming
from cin works so it's not the overloaded operator.

Bear with me because I don't understand the meaning of your words. What
in "istringstream(strTest) >> week;" is non-const? What do you mean
by "You need a named object (not temporary)."?


After fixing syntax errors and removing "(uint16_t)", your code compiled
and executed fine under VC++ v7.1 and VC++ v8, and MIPSpro 7.4 compilers.
I was unable to test with Comeau online since the server is not responding
but I am sure it would also compile it.


Thanks Victor. How did you fix the non-const blah blah above?

istringstream is(strTest); // named object (not a temporary)
is >> week;

V
 
B

Ben Pope

Randy said:
Right. Sorry about that.


Yes there is - see ISO C 99.

How is C99 relevant to C++?

>
> Here you are mistaken. If I replace the typedef with a simple enum, I
> get
>
> over.cpp:12: error: `WEEK' is not a type
>
> You need to typedef it if you want to declare variables of that type.


Perhaps you should be writing C++ code and using a C++ compiler.

Or if you want to use C, maybe you should go to some place where C is
relevant.


Ben Pope
 
R

Randy

Randy said:
A typedef never defines a new type. It defines a synonym for an existing
type. Jay's discussion is correct:

OK. OK, OK! I'll relent. This does appear to be the viewpoint most
widely used
(it's in K&R). I guess I just never thought of it that way.

To me, something like

struct Car
{
uint16 year;
char[32] color;
};

is not a "permanent" definition of a type but a temporary one. That's
why,
to use it, you have to write

struct Car myCar;

instead of just

Car myCar;

To me, the typedef actually defines the type permanently - these other
things are temporary.

Semantics. But if everyone else looks at it that way, then, yeah, I'll
line up with them for the sake of communication.
No, you don't. But since you didn't include the code for you "simple
enum" it's not possible for anyone to tell what triggered that error
message.

You're right. I had written:

enum {SUN,MON,TUE,WED,THU,FRI,SAT} WEEK;

and gotten the previously-mentioned compiler error. If instead I write

enum WEEK {SUN,MON,TUE,WED,THU,FRI,SAT};

it compiles.

--RY
 
J

JustBoo

I would love to see a typedef that actually defines a type as opposed
to being an alias for one.
- Jay

I'm aware of the thread title, but if you're going to create a new
type and not just alias an intrinsic...

I'll ask this as a question. Does the keyword " class " actually do
what Jay is asking?

Class design IS type design, right? :)

"Why isn't phonetic spelled the way it sounds?"
 
B

Ben Pope

Randy said:
A typedef never defines a new type. It defines a synonym for an existing
type. Jay's discussion is correct:

OK. OK, OK! I'll relent. This does appear to be the viewpoint most
widely used
(it's in K&R). I guess I just never thought of it that way.

To me, something like

struct Car
{
uint16 year;
char[32] color;
};

is not a "permanent" definition of a type but a temporary one. That's
why,
to use it, you have to write

struct Car myCar;

instead of just

Car myCar;

To me, the typedef actually defines the type permanently - these other
things are temporary.

Wrong again.
Semantics. But if everyone else looks at it that way, then, yeah, I'll
line up with them for the sake of communication.

Yeah, speaking the same language helps. Here, we speak C++ and English.

Ben Pope
 
R

Randy

Yes there is - see ISO C 99.
Then you need to rewrite your program in C 99 and post to comp.lang.c.
C++ Standard only refers to C 90 at this point.

Like that, Victor? As if the separation of the two has historically
been clearly defined...
istringstream is(strTest); // named object (not a temporary)
is >> week;

Thanks.
 
P

Pete Becker

Randy said:
to use it, you have to write

struct Car myCar;

instead of just

Car myCar;

You need to figure out which language you're programming in, and post to
the appropriate newsgroup. That's true for C, but not for C++. This is a
C++ newsgroup, and, if you're using iostreams, you're writing C++ code.

To me, the typedef actually defines the type permanently - these other
things are temporary.

Semantics. But if everyone else looks at it that way, then, yeah, I'll
line up with them for the sake of communication.

It's more than semantics. It's deep meaning: names that refer to the
same type can be used interchangeably; names that refer to different
types cannot.
You're right. I had written:

enum {SUN,MON,TUE,WED,THU,FRI,SAT} WEEK;

That defines an object named WEEK whose type is an unnamed enumeration
whose enumerators are SUN, MON, etc.
and gotten the previously-mentioned compiler error. If instead I write

enum WEEK {SUN,MON,TUE,WED,THU,FRI,SAT};

it compiles.

Yup.
 

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
474,431
Messages
2,571,679
Members
48,796
Latest member
Greg L.

Latest Threads

Top