Date
2011-12-03.15:02:48
Message id
5946

Content

Shouldn't move_iterator be specialized so that if the iterator it wraps returns a prvalue when dereferenced, the move_iterator also returns by value? Otherwise, it creates a dangling reference.

Howard: I believe just changing move_iterator<I>::reference would do. A direction might be testing on is_reference<iterator_traits<I>::reference>, or is_reference<decltype(*declval<I>())>.

Daniel: I would prefer to use a consistent style among the iterator adaptors, so I suggest to keep with the iterator_traits typedefs if possible.

using reference = typename conditional<
  is_reference<typename iterator_traits<Iterator>::reference>::value,
  value_type&&,
  value_type
>::type;

We might also want to ensure that if Iterator's reference type is a reference, the referent is equal to value_type (after removal of cv-qualifiers). In general we have no such guarantee.

Marc: In the default case where we don't return value_type&&, should we use value_type or should we keep the reference type of the wrapped iterator?

Daniel: This suggestion looks appealing at first, but the problem here is that using this typedef can make it impossible for move_iterator to satisfy its contract, which means returning an rvalue of the value type (Currently it says rvalue-reference, but this must be fixed as of this issue anyway). I think that user-code can reasonably expect that when it has constructed an object m of move_iterator<It>, where It is a valid mutable iterator type, the expression

It::value_type&& rv = *m;

is well-formed.

Let's set R equal to iterator_traits<Iterator>::reference in the following. We can discuss the following situations:

  1. R is a reference type: We can only return the corresponding xvalue of R, if value_type is reference-related to the referent type, else this is presumably no forward iterator and we cannot say much about it, except that it must be convertible to value_type, so it better should return a prvalue.
  2. R is not a reference type: In this case we can rely on a conversion to value_type again, but not much more. Assume we would return R directly, this might turn out to have a conversion to an lvalue-reference type of the value type (for example). If that is the case, this would indirectly violate the contract of move_iterator.

In regard to the first scenario I suggest that implementations are simply required to check that V2 = remove_cv<remove_reference<R>::type>::type is equal to the value type V1 as a criterion to return this reference as an xvalue, in all other cases it should return the value type directly as prvalue.

The additional advantage of this strategy is, that we always ensure that reference has the correct cv-qualification, if R is a real reference.

It is possible to improve this a bit by indeed supporting reference-related types, this would require to test is_same<V1, V2>::value || is_base_of<V1, V2>::value instead. I'm unsure whether (a) this additional effort is worth it and (b) a strict reading of the forward iterator requirements seems not to allow to return a reference-related type (Whether this is a defect or not is another question).