If I turn off libc++ and build with libstdc++ then all is well. Obviously, I can work around this by making FooComparator::operator() const, but I'd like to understand whether this is a problem with libc++ being too strict, or whether the standard (both C++03 and C++11) does in fact require that the comparator's operator() be const (in which case the fact that it works with libstdc++ is a happy accident).

Note: It is not possible to resolve this problem solely based on the fact that the map constructor accepts const Compare &; because Table 102 specifies that the map takes a copy of the comparator object. (This point was originally made by Kerrek SB on an answer that is now deleted).
–
Matt McNabbJul 29 '14 at 1:41

1 Answer
1

Well, yes: The comparator is a subobject of the map itself, one way or another (maybe a member; usually a base class of some inner implementation class). If you have a constant reference to the map, the comparator still needs to be usable for lookup, so the operator needs to be const.

I agree with the argument you are making, but I'm curious about how the standards (03, 11) state this. libstdc++ seems happy to instantiate a map with a comparator with a non-const operator() as long as you don't invoke that comparator in a constness violating fashion, while libc++ is not so permissive. Does the requirement that the comparator be const depend on the usage of the map? How do the standards state this, etc.
–
acmOct 30 '12 at 23:23

@acm: I don't think it's explicitly stated, but it's basically a consequence of all the other associative container requirements.
–
Kerrek SBOct 30 '12 at 23:28

1

I know I'm nitpicking, because clearly the practical answer is "just make it const already". However, it seems to me that either it is legal to instantiate std::map with a comparator with non-const operator() as long as you don't use the map in such a way as to require constness (in which case libc++ seems to have an error where it requires comparator constness in a non-const context), or it isn't legal, and libstdc++ should reject the code above, but doesn't. Or does this somehow fall within implementation defined behavior, and so both are correct?
–
acmOct 30 '12 at 23:58

1

@Nemo: The standard specifies the signatures of various accessor functions, and those functions in turn are specified to use the comparator. The comparator is required to be owned by the container. So if the accessor function is const, then the comparator must support that. Thus the comparator's operator must be const for those use cases, and thus always. If the implementation allows using certain non-const accessors with a non-const operator, then that's not a contradiction.
–
Kerrek SBOct 31 '12 at 1:04

1

@Nemo: that's a different issue. auto_ptr is formally copy-constructible, but it doesn't have the right semantics. So the standard specifies what it means for an object to be copyable (i.e. the copy is the same as the original) and mandates that your element type be such (at the pain of undefined behaviour). The equivalent requirement for the comparison object also exists: the standard requires that repeated calls always give the same result.
–
Kerrek SBOct 31 '12 at 12:18