Standard 23.1 - std::map::value_type must be assignable?

M

massysett

I'm puzzled about part of the standard. 23.1 states that items stored
in a container must be assignable. Therefore, the items in a map--that
is, std::pair<const Key, value> must be assignable. However, such a
pair--with the const Key--is not assignable.

My concern is more than academic; take for instance the following code
to make a copy of a map while eliminating some of the elements:

#include <map>
#include <algorithm>

typedef std::map<char, int> MapType;

bool predicate(const MapType::value_type& x)
{
return x.second > 1;
}

int main()
{
MapType bigMap;
bigMap['a'] = 1;
bigMap['b'] = 2;

MapType littleMap;

// This shouldn't work, right? Standard 23.1 says objects in
// container must be assignable, but MapType::value_type is
// std::pair<const char, int> which is NOT assignable
std::remove_copy_if(bigMap.begin(),
bigMap.end(),
std::inserter(littleMap, littleMap.end()),
&predicate);
return 0;
}

This compiles fine on g++ 4.1.2, but I want to make sure I'm not
writing nonstandard code. That leaves me with two questions:

1) is there part of the standard that I'm missing that describes how
maps can have values of std::pair<const Key, value> even though that
pair is not assignable?

2) is the sample code above standard compliant, and if not, how should
I accomplish something like this?

Thanks,
Omari
 
J

Jim Langston

massysett said:
I'm puzzled about part of the standard. 23.1 states that items stored
in a container must be assignable. Therefore, the items in a map--that
is, std::pair<const Key, value> must be assignable. However, such a
pair--with the const Key--is not assignable.

My concern is more than academic; take for instance the following code
to make a copy of a map while eliminating some of the elements:

#include <map>
#include <algorithm>

typedef std::map<char, int> MapType;

bool predicate(const MapType::value_type& x)
{
return x.second > 1;
}

int main()
{
MapType bigMap;
bigMap['a'] = 1;
bigMap['b'] = 2;

MapType littleMap;

// This shouldn't work, right? Standard 23.1 says objects in
// container must be assignable, but MapType::value_type is
// std::pair<const char, int> which is NOT assignable
std::remove_copy_if(bigMap.begin(),
bigMap.end(),
std::inserter(littleMap, littleMap.end()),
&predicate);
return 0;
}

This compiles fine on g++ 4.1.2, but I want to make sure I'm not
writing nonstandard code. That leaves me with two questions:

1) is there part of the standard that I'm missing that describes how
maps can have values of std::pair<const Key, value> even though that
pair is not assignable?

2) is the sample code above standard compliant, and if not, how should
I accomplish something like this?

Consider assignable as x = y. The thing is that the key and the value must
be assignable, you need an assignment operator, either default or custom.
The reason being that values are loaded into the map using assignment. A
char is assignable ( ignore the constaness for now ) and so is an int.

The map itself does not have to treat the key as const internally, the
interface does. It is extremely easy to convert a non-const something to a
const something, just not as easy the other way around.

Notice the standard says objects in the container. That is refering to the
key and the value, not the std::pair.
 
S

Salt_Peter

I'm puzzled about part of the standard. 23.1 states that items stored
in a container must be assignable. Therefore, the items in a map--that
is, std::pair<const Key, value> must be assignable. However, such a
pair--with the const Key--is not assignable.

not while they are in the associative container, that is.
My concern is more than academic; take for instance the following code
to make a copy of a map while eliminating some of the elements:

#include <map>
#include <algorithm>

typedef std::map<char, int> MapType;

bool predicate(const MapType::value_type& x)
{
return x.second > 1;

}

int main()
{
MapType bigMap;
bigMap['a'] = 1;
bigMap['b'] = 2;

MapType littleMap;

// This shouldn't work, right? Standard 23.1 says objects in
// container must be assignable, but MapType::value_type is
// std::pair<const char, int> which is NOT assignable

Sorry, I don't see any assignments.
Or did you think that copy construction is assignment?
its not, not even close.
std::remove_copy_if(bigMap.begin(),
bigMap.end(),
std::inserter(littleMap, littleMap.end()),
&predicate);
return 0;

}

This compiles fine on g++ 4.1.2, but I want to make sure I'm not
writing nonstandard code. That leaves me with two questions:

1) is there part of the standard that I'm missing that describes how
maps can have values of std::pair<const Key, value> even though that
pair is not assignable?

While the standard does require that Key to be assignable, it doesn't
mean that the map can store the pair as such. Basicly, you might need
to extract an item from the associative container(and remove it),
modify its key - and then reinserted it (letting the map reorder
according to the new key and the compare object to maintain weak
ordering).
Hence the key is assigneable, but not while its in the associative
container.

Imagine if you couldn't construct a
std::vector< Key > keys;
from a std::map said:
2) is the sample code above standard compliant, and if not, how should
I accomplish something like this?

I see no problems with it as is, though it doesn't corralate with the
problem stated at the top.
 
J

jkherciueh

massysett said:
I'm puzzled about part of the standard. 23.1 states that items stored
in a container must be assignable. Therefore, the items in a map--that
is, std::pair<const Key, value> must be assignable. However, such a
pair--with the const Key--is not assignable.

That observation is an important part of defect report 276:

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#276

The report remarks:

"It should be noted that there exists a valid and non-contradictory
interpretation of the current text. The wording in 23.1/3 avoids
mentioning value_type, referring instead to "objects stored in a
container." One might argue that map does not store objects of type
map::value_type, but of map::mapped_type instead, and that the Assignable
requirement applies to map::mapped_type, not map::value_type.


Best

Kai-Uwe Bux
 
M

massysett

That observation is an important part of defect report 276:

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#276

The report remarks:

"It should be noted that there exists a valid and non-contradictory
interpretation of the current text. The wording in 23.1/3 avoids
mentioning value_type, referring instead to "objects stored in a
container." One might argue that map does not store objects of type
map::value_type, but of map::mapped_type instead, and that the Assignable
requirement applies to map::mapped_type, not map::value_type.

I thought of that too, but the argument falls apart. 23.1/5: "X
denotes a container class containing objects of type T." Table 65 says
X::value_type returns T. 23.3.1: "typedef pair <const Key, T>
value_type". pair <const Key, T> is not assignable.

At best the standard is confusing on this point; at worst it is simply
inconsistent.
 

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,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top