using two strings values as a key to the map

P

puzzlecracker

I need to be able to map two string to some value in the map. I
consider two alternatives to implement : using pair class or using a
separate class/struct containing two member strings. I prefer the
latter for it's more descriptive. However, in the latter
implementation (equivalent of which is shown below), I got some
compiler errors on gcc 3.3.1 with MyClass.


#include<map>
#include <string>

using namespace std;

struct MyClass
{
MyClass ( const string &a, const string & b):a_(a),b_(b){}
string a_;
string b_;
};

inline bool operator <(const MyClass &a, const MyClass & b)
{
return a.a_<b.a_ ||(a.a_==b.a_?a.b_<b.b_:false);
}
int main()
{
//This caused the error
map<MyClass, MyClass *>m;
MyClass my("Foo", "Bar");
m.find(my);

//This fixed it
map<MyClass, MyClass *>m1;
m1.find(MyClass("Foo","Bar"));
}

Unfortunately, I can't show the compiler error, b/c I couldn't
reproduce it at home, only at work. Perhaps, error I'll post it
tomorrow.

I want to see if anyone can see the issue here or suggest an
alternative design.

Thanks
 
N

newbarker

I need to be able to map two string to some value in the map. I
consider two alternatives to implement : using pair class or using a
separate class/struct containing two member strings. I prefer the
latter for it's more descriptive. However, in the latter
implementation (equivalent of which  is shown below), I got some
compiler errors on gcc 3.3.1 with MyClass.

#include<map>
#include <string>

using namespace std;

struct MyClass
{
     MyClass ( const string &a, const  string  & b):a_(a),b_(b){}
     string a_;
     string b_;

};

inline bool operator <(const MyClass &a, const MyClass & b)
{
     return a.a_<b.a_ ||(a.a_==b.a_?a.b_<b.b_:false);}

int main()
{
   //This caused the error
    map<MyClass, MyClass *>m;
    MyClass my("Foo", "Bar");
    m.find(my);

//This fixed it
    map<MyClass, MyClass *>m1;
    m1.find(MyClass("Foo","Bar"));

}

Unfortunately, I can't show the compiler error, b/c  I couldn't
reproduce it at home, only at work. Perhaps,  error I'll post it
tomorrow.

I want to see  if anyone can see the issue here or suggest an
alternative  design.

Thanks

That compiled ok here using Microsoft Visual C++ 2003 (7.1). I would
use a std::pair myself. Less to write and I think it's MORE
descriptive and people know exactly how a std::pair works but need to
look at the home-grown entity including the operator< implementation
before they're comfortable with it.

Regards,

Pete
 
B

Barry

I need to be able to map two string to some value in the map. I
consider two alternatives to implement : using pair class or using a
separate class/struct containing two member strings. I prefer the
latter for it's more descriptive. However, in the latter
implementation (equivalent of which is shown below), I got some
compiler errors on gcc 3.3.1 with MyClass.

#include<map>
#include <string>

using namespace std;

struct MyClass
{
MyClass ( const string &a, const string & b):a_(a),b_(b){}
string a_;
string b_;

};

inline bool operator <(const MyClass &a, const MyClass & b)
{
return a.a_<b.a_ ||(a.a_==b.a_?a.b_<b.b_:false);}

int main()
{
//This caused the error
map<MyClass, MyClass *>m;
MyClass my("Foo", "Bar");
m.find(my);

//This fixed it
map<MyClass, MyClass *>m1;
m1.find(MyClass("Foo","Bar"));

}

Unfortunately, I can't show the compiler error, b/c I couldn't
reproduce it at home, only at work. Perhaps, error I'll post it
tomorrow.

I want to see if anyone can see the issue here or suggest an
alternative design.


The standard containers require the types to be Assignable.
In your code, MyClass is not,
if the compiler have concept checking, compile error would be
produced.

HTH.
 
A

anon

Your compiler is too old. I have no problems using g++ 4.1.3
The standard containers require the types to be Assignable.
In your code, MyClass is not,
if the compiler have concept checking, compile error would be
produced.

This compiles using g++ 4.1.3

int main()
{
MyClass a("Foo1", "Bar1");
MyClass b("Foo2", "Bar2");

b = a;

std::cout<<b.a_<<std::endl;
std::cout<<b.b_<<std::endl;
}

(off course, include iostream)

Am I causing undefined behavior somehow?
 
P

puzzlecracker

The standard containers require the types to be Assignable.
In your code, MyClass is not,
if the compiler have concept checking, compile error would be
produced.

HTH.

Assignable?

Do I need a copy constructor and operator =?


How would it be implemented with pair?

Thanks
 
T

Thomas J. Gritzan

Assignable?

Do I need a copy constructor and operator =?

No, Barry is wrong. Your struct is copy constructable and assignable.

The compiler automatically defines a copy constructor and a copy
assignment operator for you. These work element-wise, that is, if all
elements of the struct are copy constructable and assignable, the struct
is, too.
How would it be implemented with pair?

Just replace MyClass with std::pair<std::string,std::string>.
std::pair already has a correct operator< implemented.

You can then initialize a std::pair with the make_pair helper function:

m1.find( std::make_pair("Foo","Bar") );
 
P

puzzlecracker

No, Barry is wrong. Your struct is copy constructable and assignable.

The compiler automatically defines a copy constructor and a copy
assignment operator for you. These work element-wise, that is, if all
elements of the struct are copy constructable and assignable, the struct
is, too.


Just replace MyClass with std::pair<std::string,std::string>.
std::pair already has a correct operator< implemented.

You can then initialize a std::pair with the make_pair helper function:

m1.find( std::make_pair("Foo","Bar") );

how is operator< implemented if I have two strings not just one. I
think, i still need to supply the functor or operator <.
 
J

James Kanze

The standard containers require the types to be Assignable.
In your code, MyClass is not,

It looks Assignable to me. What makes you say that it isn't
Assignable?
if the compiler have concept checking, compile error would be
produced.

I have no problem compiling it with g++ (4.1.0), with all
checking turned on.
 
J

James Kanze

No, Barry is wrong. Your struct is copy constructable and
assignable.
The compiler automatically defines a copy constructor and a
copy assignment operator for you. These work element-wise,
that is, if all elements of the struct are copy constructable
and assignable, the struct is, too.
Just replace MyClass with std::pair<std::string,std::string>.
std::pair already has a correct operator< implemented.
You can then initialize a std::pair with the make_pair helper function:
m1.find( std::make_pair("Foo","Bar") );

But why doesn't his operator< work? It looks OK to me (although
I've have written the expression:

return a.a_ < b.a_ || (a.a_ == b.a_ && a.b_ < b.b_) ;

..)

For once someone is doing the right thing, and trying to write
readable code (rather than using std::pair). Let's not
discourage him.
 
T

Thomas J. Gritzan

James said:
But why doesn't his operator< work? It looks OK to me (although
I've have written the expression:

It looks ok to me, too, and Comeau accepts it. It might not be the
original copy'n'pasted code.
return a.a_ < b.a_ || (a.a_ == b.a_ && a.b_ < b.b_) ;

.)

For once someone is doing the right thing, and trying to write
readable code (rather than using std::pair). Let's not
discourage him.

Heh, he asked for std::pair, don't blame me! :)

In a hobby project I had a
std::map< std::pair<int, std::pair<int,int> >, valueType >,
and it was really ugly.

In the long term, using a struct with a good name (or at least a typedef
for std::pair) is the better idea.
 

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

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,192
Latest member
KalaReid2

Latest Threads

Top