3

In the current draft of C++23s flat_map design, the type flat_map::reference is defined as pair<const key_type&, mapped_type&>, i.e. it is not a reference to flat_map::value_type = pair<key_type, mapped_type>. (This seems to be mandatory, since the keys and values are stored not as pairs, but in two separate containers.) Thus, the iterators must be some proxy-class.

This makes me think: Is a flat_map actually even an STL container, similar to std::vector<bool> isn't one?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
tommsch
  • 582
  • 4
  • 19
  • The "STL" was/is a very old library (the Standard Template Library) that was incorporated into the C++98 standard library. Is any later thing added to the standard part of STL? No. Is it part of the standard library, yes. – Jesper Juhl Nov 13 '22 at 00:43
  • @JesperJuhl This is true in a historical sense, but nowadays it gets more ambiguity. In the context of WG21 discussions, "STL" may denote [Stephan T. Lavavej](https://nuwen.net/stl.html), who is the maintainer of [microsoft/STL](http://github.com/microsoft/STL). The latter *is* an up-to-date implementation of the current ISO C++ standard library and IIRC Mr. STL strongly insists on that name. – FrankHB Jan 24 '23 at 07:53

2 Answers2

3

The standard defines what a "container" is in [container.reqmts]. Among these requirements is:

typename X::reference

  • Result: T&

So yes, std::flat_map is not a container.

But it never claims to be; it is a "container adapter":

A flat_­map is a container adaptor...

Note that like std::stack/queue/priority_queue, std::flat_set/map take container types as template parameters.

It should also be noted that, while they are not containers, they are ranges as defined by the C++20 range library's concepts. The C++20 ranges concepts allow for proxy ranges where the reference type need not be a value_type&.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 1
    The [standard](https://timsong-cpp.github.io/cppwp/flat.map#overview-2) says "A flat_­map meets all of the requirements of a container.". But it is not entirely accurate, is it? I'm feeling a bit uncertain about this claim in the standard. – HarryLeong Mar 01 '23 at 10:01
1

Author of P2767R0 here. This is all pedantic how-many-angels-can-dance-on-the-head-of-a-pin stuff, so while I'm going to present my own pedantic answer, please understand that I'm not claiming anyone else's different answer is necessarily wrong. It's all equally irrelevant in practice.

(1) flat_map itself (the class template) is not a container; it's a container adaptor. Even vector isn't a container; it's a template for stamping out containers. A "container adaptor," in my worldview, is a template for stamping out containers, where one of the template parameters is itself a container. Compare the usage of "iterator adaptor" (and "view adaptor" in Ranges). "Class template reverse_iterator is an iterator adaptor," but an object of type reverse_iterator<int*> is (simply) an iterator. flat_set is a container adaptor; an object of type flat_set<int> is (simply) a container.

Notice [vector.overview] doesn't say "Class template vector is a sequence container..."; it says "A vector is a sequence container..." That is, an object of type some-specialization-of-vector is (simply) a container.

"But [sequences.general] says, ‘The headers <array>, <deque>, <forward_list>, <list>, and <vector> define class templates that meet the requirements for sequence containers!’ How do you square that with your claim that class templates aren't containers?"

Well, surely you agree that <array> doesn't define any class templates that meet the sequence-container requirements, right? We can argue about vector<bool>, but array definitely isn't a container. So that sentence is wrong on the face of it.

(Meanwhile, TIL that C++23's [vector.bool]/8 implies that the user is allowed to provide "a program-defined specialization" for vector<bool, A>. Who knows what such a specialization might do!)

(2) As far as I'm concerned, flat_map<int, int> is a container. As you observed, [flat.map]/2 says explicitly that flat_map "meets all of the requirements of a container." Sure, on one hand it seems clearly to fail the X::reference requirement... but on the other hand, the standard says it meets all the requirements! Something's got to give; and I think it makes vastly more sense to assume that the C++98-era [container.reqmts] is out of sync with C++23's reality, than to assume that the C++23-era [flat.map] is out of sync. Someone just needs to update [container.reqmts] to handle the modern possibility of proxy reference types.

Quuxplusone
  • 23,928
  • 8
  • 94
  • 159
  • *Someone just needs to update [container.reqmts] ...* Thats a good point, but it also implies that we cannot really rely on the C++ standard. What's a container, meeting all the container requirements, worth then? I may believed in the wrong concept that the standard is some kind of mathematical truth without errors (Which actually would make sense, since C++ is a language for deterministic computers). – tommsch Jul 04 '23 at 06:54
  • "I may [have] believed in the wrong concept that the standard is some kind of mathematical truth without errors" — Oh yeah, absolutely not. Take it from a contributor: the Standard is just a paper document, written in English, that changes constantly (such that a new edition with major changes comes out every 3 years). Those who edit it have the goal of making it reflect the truth; but if it already *did* reflect the truth, there'd be no reason to edit it any more. :) – Quuxplusone Jul 04 '23 at 16:01