Can a container iterator get something other than an lvalue?

I more or less came to the conclusion that it is impossible to write a correspondence container whose value_type is not stored directly in the container. I think this is unfortunate because I often end up wanting to have containers where the type of the value is either partially computed or assembled from non-contiguous parts (examples below, but not directly related to the question). I know how to write iterators that use proxy objects, although this is pretty annoying. But now I am wondering if the place in the C ++ standard is really for such animals. There are probably too many verbal words; tl version; dr is simple: what does paragraphs 1 and 6 of & section 24.2.5 really mean and to what extent will they violate the obvious meanings of standard algorithms? Or, in other words, how to interpret them to allow proxy iterators?

As Pete Becker points out, there really is nothing to make my containers meet the requirements for standard library containers. But in order to use a container with many standard algorithms, it must either have a compatible iterator with at least forward_iterator_tag , or it must lie about it, but still satisfy the operational (if not formal) requirements that a particular algorithm imposes on its iterators .

Here are my thoughts:

Table 96 ("23.2.1), container requirements, includes:

 Expression Return type Assertion/note ------------ ------------- --------------------- X::iterator iterator type any iterator category whose value that meets the type is T forward iterator requirements. Convertible to const_iterator. a.begin() iterator; const_iterator for constant a. 

Now, go ahead iterator:

& section; 24.2.5, paragraph. one:

The X class or pointer type satisfies the requirements of the advanced if & hellip;

- if X is a mutable iterator, reference is a reference to T ; if X is an iterator of const, reference is a reference to const T

It is true that for *a there is no direct requirement to return reference (where a is of type X ). Requirements:

from table 107 (input iterators) *a must be "convertible to T" if a is unsolvable.

from table 106 (iterators) *r must be of type reference , where r is of type X& and is nonsense.

However, Table 106 also indicates that ++r returns X& , therefore *++r should be a reference . In addition, (according to table 107), *a++ should be a reference , although (table 109) a[n] only needs to be "converted to link". I must say that I do not see how *a , where a is of type X and *r , where r is of type X& , may be different, but maybe I lack some subtleties.

Maybe there is a small room for manicure, but not so much; at some point you need to be prepared to create T , if you really don't have it in the container so you can provide it with a link.

But the kicker

& section; 24.2.5, paragraph. 6 ( a and b are values ​​of type X ): If a and b are dereferenced, then a == b if and only if *a and *b attached to the same object.

I cannot find a formal definition of bound to , but it seems to me that the usual strategy for creating iterators of non-addressable objects is to create a proxy object, usually stored inside the iterator itself. In this case, it would require an extremely generous understanding of what “connected” means to interpret 24.2.5 / 6 in some way, except to prohibit comparisons of correspondence between two different iterator objects, even if they logically indicate the same position in the container.

On the other hand, I note that Dietmar Kühl, who should know, in his answer to this question says that:

C ++ 2011 got relaxed requirements, and iterators don't have to give an lvalue

So, can an iterator return a proxy server or not? If possible, what is the nature of such a proxy? Where does my reasoning that such an iterator is inappropriate fail?


As promised, several containers, the effective values ​​of value_types will not be stored in the container in the container:

1) A compact associative container whose key and value types can be more efficiently stored in two separate vectors. (Storing keys in a vector can also improve cache compatibility, as well as reduce distribution overhead.)

2) A vector<T> , which masquerades as map<integer_type, T> , which simplifies the interaction with other types of map<X, T> .

3) A logical container formed by holding several other containers together, creating a logical value_type, which is a tuple references to value types for compressed containers. (In some applications, one or more compressed containers can be fully calculated either as a function of other values ​​or as a serial number.)

4) A view of an aggregated type container that has only some of the values. (It is possible that both the main container and the view are tuples in which the list of view type types is a subset, possibly in a different order of types of base containers).

I am sure that other people can easily add to this list; these are only those that I have earned anyway over the past couple of months.

+8
c ++ c ++ 11
source share
2 answers

Do not limit yourself to thinking of a “conformance container”: there is nothing in the standard that depends on its availability. Think of container requirements as an abbreviated description of the container requirements that are defined in the standard. Nothing more. As long as the iterators created by your container are valid, you are fine with all the relevant algorithms and, presumably, with the algorithms you write yourself.

+2
source share

The best model is std::vector< bool > . It is as close to capabilities as possible, but its iterators give proxies.

The standard even states that std::vector<bool>::reference is a class. However, the container requirements table indicates that X::reference gives "l value T." Therefore, it is strictly incompatible.

But iterators are not tied to T The iterator value_type must be T and meet the requirements of the input iterator, reference must convert to value_type .

As Pete Becker mentions, requirement tables are fairly wide blankets, and individual algorithms determine what they need. Only an algorithm that requires reference really be a link will break, which seems to simply indicate the obvious.

+2
source share

All Articles