Overloading << to accept "multiple right parameters"

B

Bubba

Greetings,

I don't know whether I have stipulated subject correctly, but this is what
I need.

There is a class that consists of a STL map<string,short>, amongst other
interfaces. Operator << should accept a string as right parameter. After
that string, it should again be possible to enter either string or number.
If number is entered, then it is associated with a map, if another string
is entered, new member of map is created. Expression must end with a
number and that number should be associated with all strings in the map.
If it doesn't, it should throw an exception.

IOW, it should look like this:

mVar1 << "string1" << 2; //one entry in map, with values "string1",2
mVar2 << "string2" << "string3" << "string4" << 10; //three map entries
//each with short
//valeu of 10

I'm simply clueless about what should I even Google for in order to
implement something like that, let alone do it. Manipulating with map STL
within the implementation is not a problem (I suppose?), but syntax and
idea behind those multiple parameters is what bugs me...

TIA!
 
B

Bubba

Robert Wessel's log on stardate 28 lip 2011
The "multiple operator" thing is an interesting hack - it isn't
actually any such thing, it just looks that way. What actually
happens with streams is that the overload for operator<< *returns*
the stream, thus the next << has the stream as its left operand, just
like the prior <<. So typically you have something like:

ostream& operator<< (ostream& os, const string& str);

and when you write:

cout << s1 <<s1;

what happens is that "cout << s1" is evaluated first and effectively
does "ostream::eek:perator<<(cout, s1)". The return value of that is
cout, so the second insert is effectively "cout << s2", and executes
as "ostream::eek:perator<<(cout, s2)".

IOW, when you define your actual function, it would be something
like:

ostream& ostream::eek:perator<< (ostream& os, const string& str)
{
/* do something with str */
return os;
}

But I'm not in to stream at all. :)

I want to overload operator << in a fashion that it can accept both string
and short as parameter and it is implemented as I described above.

For example,

void operator<< (const string &mPar) {
mMap.insert (pair<string,short>(mPar,0));
}

works if I write

mVar1 << "string1";

However, in this case

mVar1 << "string1" << "string2";

error C2296: '<<' : illegal, left operand has type 'void'
error C2297: '<<' : illegal, right operand has type 'const char [8]'

And I need

mVar1 << "string1" << "string2" << 100;

to create two entries in mMap with values <"string1",100> and
<"string2",100>.

Thanks anyway!
 
I

Ian Collins

Robert Wessel's log on stardate 28 lip 2011
The "multiple operator" thing is an interesting hack - it isn't
actually any such thing, it just looks that way. What actually
happens with streams is that the overload for operator<< *returns*
the stream, thus the next<< has the stream as its left operand, just
like the prior<<. So typically you have something like:

ostream& operator<< (ostream& os, const string& str);

and when you write:

cout<< s1<<s1;

what happens is that "cout<< s1" is evaluated first and effectively
does "ostream::eek:perator<<(cout, s1)". The return value of that is
cout, so the second insert is effectively "cout<< s2", and executes
as "ostream::eek:perator<<(cout, s2)".

IOW, when you define your actual function, it would be something
like:

ostream& ostream::eek:perator<< (ostream& os, const string& str)
{
/* do something with str */
return os;
}

But I'm not in to stream at all. :)

I want to overload operator<< in a fashion that it can accept both string
and short as parameter and it is implemented as I described above.

For example,

void operator<< (const string&mPar) {
mMap.insert (pair<string,short>(mPar,0));
}

works if I write

mVar1<< "string1";

However, in this case

mVar1<< "string1"<< "string2";

error C2296: '<<' : illegal, left operand has type 'void'
error C2297: '<<' : illegal, right operand has type 'const char [8]'

Your operator has the wrong return type for chaining. Here is a short
example of some code I've use for std::vector. Expanding for std::map
shouldn't be too hard.

#include <vector>
#include <iostream>
#include <algorithm>

template <typename T>
std::vector<T>& operator<<( std::vector<T>& vector, T v )
{
vector.push_back(v);
return vector;
}

void print( int n ) { std::cout << n << std::endl; }

int main()
{
std::vector<int> v;

v << 1 << 2;

std::for_each( v.begin(), v.end(), print );
}
 
K

Kai-Uwe Bux

Bubba said:
Greetings,

I don't know whether I have stipulated subject correctly, but this is what
I need.

There is a class that consists of a STL map<string,short>, amongst other
interfaces. Operator << should accept a string as right parameter. After
that string, it should again be possible to enter either string or number.
If number is entered, then it is associated with a map, if another string
is entered, new member of map is created. Expression must end with a
number and that number should be associated with all strings in the map.
If it doesn't, it should throw an exception.

IOW, it should look like this:

mVar1 << "string1" << 2; //one entry in map, with values "string1",2
mVar2 << "string2" << "string3" << "string4" << 10; //three map entries
//each with short
//valeu of 10

I'm simply clueless about what should I even Google for in order to
implement something like that, let alone do it. Manipulating with map STL
within the implementation is not a problem (I suppose?), but syntax and
idea behind those multiple parameters is what bugs me...

What about something like this:


#include <iostream>
#include <vector>
#include <map>
#include <string>

class example {

typedef std::map< std::string, int > table;

table data;

struct proxy {

example * where;

std::vector< std::string > stored;

proxy ( example * ptr )
: where ( ptr )
, stored ()
{}

proxy & operator<< ( std::string const & str ) {
stored.push_back( str );
return ( *this );
}

proxy & operator<< ( int i ) {
while ( ! stored.empty() ) {
(where->data)[ stored.back() ] = i;
stored.pop_back();
}
return ( *this );
}

};

public:

void dump ( std::eek:stream & ostr ) {
for ( table::const_iterator iter = data.begin();
iter != data.end(); ++iter ) {
ostr << iter->first << " : " << iter->second << "\n";
}
}

proxy operator<< ( std::string const & str ) {
return ( proxy( this ) << str );
}

};

int main ( void ) {
example a;
a << "a" << "b" << 1
<< "c" << 2;
a.dump( std::cout );
std::cout << "\n";
a << "x" << "y" << 0
<< "g" << "h" << 2
<< "b" << 0;
a.dump( std::cout );
}



Best,

Kai-Uwe Bux
 
B

Bubba

Kai-Uwe Bux's log on stardate 29 lip 2011

/snip

Thx! That's exactly what I needed. So essentially, address of class should
be returned and simply overload operator twice (once for each data type)!

Thank you once again!
 

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,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top