Skip to main content
gamedev.net
🔒 Locked

std::map 'operator =' function is unavailable

Started by bash Jan 10, 2005 at 5:33 AM 12 replies 6.6k views
Original Post
bash
bash
Okay, I'm trying to teach myself some STL and I've got vector and list down (well, in use anyway...), but having problem I just don't understand with map. I have done quite a bit of searching for this problem, and did find threads I thought were going to hit it, but didn't. This page seemed to have some good 'introduction' info on it, so I was using their examples as a starting point: http://www.roguewave.com/support/docs/sourcepro/stdlibug/9-3.html#931 Problem is, the very first thing that comes up is: ": error C2582: 'std::pair,class std::allocator > const ,long>' : 'operator =' function is unavailable" This is with no modification by me whatsoever. I've tried to make sure this isn't something specific to their implementation of map, and it's not some VC6 compiler issue. Neither of those seem possible as it's such a simple, seemingly standard, example. (I am not using any 'Rogue Wave' code, I was just using their examples for standard stuff since they were clearly written.) I've seen some posts on /nearly/ related things (same error, different situation or template) where people suggest that it is the 'const' of the string that makes it un-assignable. My first question to this is; "then why is the example that way?". But if I blindly and ignorantly just remove the 'const' the error then becomes: ": error C2679: binary '=' : no operator defined which takes a right-hand operand of type 'long' (or there is no acceptable conversion)" which I don't get either as I'm /really/ just learning how map works and since this error seems to imply a more fundamental problem, I'm just sitting here staring at it.... This must be simple, but I'm just baffled. Oh, and I guess I'll make another comment here. This is my first post. But that's irrelavent. ;) My /actual/ comment is that, for problems I've had in the past where I've searched the net aggressively looking for solutions, by far the best, most frequent, and most helpful answers and responses to people's issues I've found have been here on GameDev.net. So even before you help with this problem, thank you for helping with problems in the past. :) sherman
Zipster
Zipster
Their typedef is rather long an unncessecary, since everything beyond the first long has a default type which is equivalent to what they wrote out explicitly (the const as well). Although I suppose that's fine since it's a learning tutorial [smile]

Also, what lines give you the errors?
Deyja
Deyja
This is based on the first error message. The second is quite nearly meaningless without a line of code to go with it.

I would assume (assume meaning 'try this first') the class std::pair does not have an operator= that takes a long. In this case, the pair is instanced as std::pair. Change the offending line from "whatever_pair_is_being_assigned_to = some_long" to "whatever_pair_is_being_assigned_to.second = some_long" The tutorial writers might have had an odd implementation, or they just didn't bother to check their code. If you can't figure out how to make the changes, post the block of code it's in.

The first error message is literally saying "The function is there, but it's private or non-const or something and you can't call it." which is odd, because the second error message would then be saying "Oops, nevermind, I never had the function to begin with."
bash
bash
Hmm. I was thinking that whatever response I got would make /some/ sense to me...
I thought the .first and .second things were used when referencing an individual instance of the map but you could add to the map by using the [] convention (as the example attempts to do.) Also, for example, the MS documentation does it this way in their "months of the year" example ( MyMap["January"] = 1;)
I posted the link so I wouldn't have to paste the code in here, but I guess I need to. I will cut and paste their code in, but remove some unnecessary stuff.

-------------------------------------------------------------------------------
typedef std::map,
std::allocator long> > > friendMap;

typedef friendMap::value_type entry_type;

class telephoneDirectory {
public:
void addEntry (std::string name, long number) {
database[name] = number; // <<<------ Generates error previously posted
}
void remove (std::string name) {
database.erase (name);
}
void update (std::string name, long number) {
remove (name);
addEntry (name, number);
}
private:
friendMap database;
};
-------------------------------------------------------------------------------

zipster, it is helpful knowing that it's long and unnecessary but, as you say, it's probably good for a tutorial.
How does one know what default types are available? Meaning, since this is a map of , is there also a default allocator for , or pretty much anything other than if I want to use my own classes? ()
Also, if these are standard questions I'm asking, and there's a good, clear resource with slow, spelled out answers, you can feel free to point me there. The MSDN documentation on STL stuff only makes it more confusing. (and rarely compiles without adding things they neglected to mention)

bash
bash
ps, I do have the Stroustrup C++ book, but even his simplest explanations for things can lose me quickly...
Qw3r7yU10p!
Qw3r7yU10p!
See this thread: Making STL error messages understandable.

The way a map works is that it stores pairs of data - a key and a value. To make it quick to find a value it will sort each new key-value pair that is added to the map so that it can be looked up quickly. You are able to modify the value but modifying the key would mess up whether or not the map was sorted correctly. So the key is a constant object.

If you want to modify a key you should remove the pair and insert a new one.

typedef std::map<std::string, long> friendMap;class telephoneDirectory {    public:    void addEntry (std::string name, long number) {        database[name] = number;    }    void remove (std::string name) {        database.erase (name);    }    void update (std::string name, long number) {        remove (name);        addEntry (name, number);    }private:    friendMap database;};
bash
bash
Quote:
Original post by petewood
The way a map works is that it stores pairs of data - a key and a value. To make it quick to find a value it will sort each new key-value pair that is added to the map so that it can be looked up quickly. You are able to modify the value but modifying the key would mess up whether or not the map was sorted correctly. So the key is a constant object.

If you want to modify a key you should remove the pair and insert a new one.

*** Source Snippet Removed ***


Uhhh... Yeah, I know what a map is. That's why I'm trying to use them. Your info is certainly valid, but doesn't address my question. So again, I'm confused. Did I not present the problem properly? And you posted back the code I posted previously. Why?

I guess I will try again.

---- ignore all commentary and questions in this thread up to this point ------
--------- I'm just starting over ----------------------------------------------

In the example code I have given, why does the line:
database[name] = number; // <<<------ Generates error previously posted
generate an error when trying to compile? From all sources I can find, this is a legal, and in fact quite a common, way to add a new entry to a map.

---------- end question -------------------------------------------------------

Qw3r7yU10p!
Qw3r7yU10p!
Quote:
Original post by bash
And you posted back the code I posted previously. Why?


The typedef is different.
bash
bash
Quote:
Original post by petewood
Quote:
Original post by bash
And you posted back the code I posted previously. Why?


The typedef is different.



So, you are saying then that the original sample code from Rogue Wave that I linked to, then quoted was just wrong and that zipster's comment was incorrect?

If so, that's fine, but then I guess I'm going to be writing to Rogue Wave next to ask them what's up.

What I'm trying to find out is why the sample code, as it exists, does not compile. As opposed to "try this" type suggestions. That way, as I'm learning and looking around the web for more example/sample/tutorial type code, I will have the capability to recognize good/proper code from bad/inaccurate.

Given your modification to the existing code, what are you actually saying? Some possibilities:
- "When creating maps using default types, do not specify the "less than"s or "allocator"s"
- "Their version of STL must work differently than what I understand as 'standard' (meaning it is "non-standard")"
- "In this case, the has a which causes to not properly."

Just changing the code doesn't really help me.
Doc
Doc
Quote:
Original post by bash
typedef std::map,
std::allocator long> > > friendMap;


I think std::allocator > could be your problem. (I'm not up to speed with allocator semantics so I might be wrong.) What you have here is essentially a list of pairs of strings and longs. But you've only given it a way to allocate pairs of const strings and longs. Remove the const in that allocator template bit and see if that works.

EDIT: Nope. I'm wrong. (And my reading comprehension needs work.)

That's one weird problem you have. It could very well be an issue with VC6.
bash
bash
I guess I'll throw in now with a "sorry if I'm being harsh or rude". I'm not trying to be rude to anyone. I have no doubt I could fiddle with the code and make it compile. And maybe even run... ;) However, what I'm really interested in is understanding a bit better before I go fiddling.

Perhaps it's unfortunate that my googling for basic map info led me to the Rogue Wave site, but perhaps not. Seems like things that don't work right off often teach you more.

So, just for more info, they have this page: http://www.roguewave.com/support/docs/hppdocs/stdref/map.html#Warning
where at the /very/ bottom there is some map related info, in particular talking about Compare and Allocator arguments. Mentioning "Also, many compilers do not support default template arguments..."
Again, this page is generally a clear info page(to me), but I don't know if (my version of) the MS compiler is "one of those". Most of those replying to this thread seem to be on the side that the default arguments are a given and that the sample code which specifies the arguments is unnecessary or even potentially "the problem". Comments on this are welcome also.


Sorry if I seem hooked on this RogueWave stuff, I'm not. Just want to understand. :)
Deyja
Deyja
Wow, their code is ugly. Something is deffinitly going wrong somewhere in std::map, though. Operator[] should return a long& in this case, but seems to be returning the pair instead!

class telephoneDirectory {public://Don't actually see anything wrong with this one. :/void addEntry(const std::string& name, long number) {//This is what seems to be returning a pair instead of a long&.//You could try database[name].second = number; If that works, your STL //is borked.//database[name] = number; //This should work, though.std::map<std::string,long>::iterator I = database.find(name);if (I == database.end()){database.insert(name,number); //If you haven't got this overload either,//try database.insert(std::pair<std::string,long>(name,number));}else{I->second = number;}}//Now this was just wrong.void remove(const std::string& name) {database.erase(database.find(name));}void update(const std::string& name, long number) {remove(name);addEntry(name, number);}private:std::map<std::string,long> database;};


I removed the typedefs because one was used once, and the other wasn't used at all.

It works find for me in VC6.0.
Zipster
Zipster
Quote:
How does one know what default types are available? Meaning, since this is a map of , is there also a default allocator for , or pretty much anything other than if I want to use my own classes? ()

When I say "default types," I mean that you don't have to type them in yourself and that the template was written to fill in what you don't specify. For example, if you take a close look at that typedef you'll see that everything beyond the key and the value can be expressed in terms of those key and value types, and as such the template was written so you don't have to type those in all the time. Things like your sorting predicate and the allocator are standard things that don't change all the time, so it's nice not to have to write it out.

Other than that, it will work with most types you use, since all the compiler does is plug those types in and see if they work. Whether it works sometimes depends on if the supplied types meet some requirements (such as overloading certain operators), but for std::string and a built-in type as your key/value, there shouldn't be anything wrong there. Sorry I can't elaborate any further, STL and templates are a large subject and it can be hard to explain :/

Quote:
So, you are saying then that the original sample code from Rogue Wave that I linked to, then quoted was just wrong and that zipster's comment was incorrect?

My statement can be easily verified with MSDN. It lists all the default values for these templates. That's actually how I checked to see that const was specified by default. This is the prototype for the overloaded bracket operator:
Type& operator[](   const Key& _Key);

From this point of view, that error doesn't even make any sense. I'm thinking that your implementation is so ass backwards that it's returning a reference to the pair object instead. But VC6 is notorious for having a really bad STL implementation. See if this code works, and if it does, then get yourself STLPort [smile]:
database[name].second = number;

first and second and the name of the variables used in a pair to store the key and value.
bash
bash
Thanks to all who responded.

Though I did not solve "The Riddle of the Rogue Wave map sample", your comments were very helpful in my general understanding of the topic, and I will be able to move on with my life now. ;)

For my purposes this time, I went with another approach to my actual implementation (not using maps) simply because I wasn't comfortable enough with them yet. I used a class that looks things up manually in a vector, which is okay in this situation since there aren't a lot of entries and they don't need to be looked up often enough to worry about the benefits of the hashing in a map.


signing off from this thread.

bash

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.