Section: 16.2.1 [networking.ts::buffer.reqmts.mutablebuffersequence] Status: C++23 Submitter: Vinnie Falco Opened: 2016-10-05 Last modified: 2023-11-22
Priority: Not Prioritized
View all issues with C++23 status.
Discussion:
Addresses: networking.ts
We propose to relax the ForwardIterator requirements of buffer sequences
in [networking.ts] by allowing buffer sequence iterators to return rvalues when
dereferenced, and skip providing operator->
.
A paraphrased explanation of why the referential equality rules of ForwardIterator
are harmful to the buffer sequence requirements comes from N4128,
3.3.7 "Ranges For The Standard Library":
The [networking.ts] dependence on ForwardIterator in the buffer sequence requirements ties together the traversal and access properties of iterators. For instance, no forward iterator may return an rvalue proxy when it is dereferenced; the ForwardIterator concept requires that unary
operator*
return an lvalue. This problem has serious consequences for lazy evaluation that applies transformations to buffer sequence elements on the fly. If the transformation function does not return an lvalue, the range's iterator can model no concept stronger than InputIterator, even if the resulting iterator could in theory support BidirectionalIterator. The result in practice is that most range adaptors today will not be compatible with [networking.ts], thereby limiting the types that [networking.ts] can be passed, for no good reason.
Consider a user defined function trim
which lazily adapts a
ConstBufferSequence
, such that when iterating the buffers in the new
sequence, each buffer appears one byte shorter than in the underlying sequence:
#include <boost/range/adaptor/transformed.hpp> struct trim { using result_type = const_buffer; result_type operator()(const_buffer b) { return const_buffer{b.data(), b.size() - 1}; } }; template <ConstBufferSequence> auto trim(ConstBufferSequence const& buffers) { using namespace boost::adaptors; return buffers | transformed(trim{}); }
trim
returns a BidirectionalRange, whose
const_iterator
returns an rvalue when dereferenced. This breaks the
requirements of ForwardIterator. A solution that meets the referential equality
rules of ForwardIterator, would be to evaluate the transformed
sequence upon construction (for example, by storing each transformed
const_buffer
in a vector
). Unfortunately this work-around is
more expensive since it would add heap allocation which the original example avoids.
The requirement of InputIterator operator->
is also
unnecessary for buffer sequence iterators, and should be removed. Because
[networking.ts] only requires that a buffer sequence iterator's
value_type
be convertible to const_buffer
or
mutable_buffer
, implementations of [networking.ts] cannot assume the
existence of any particular member functions or data members other than an
implicit conversion to const_buffer
or mutable_buffer
.
Removing the requirement for operator->
to be present, provides
additional relief from the referential equality requirements of
ForwardIterator and allows transformations of buffer sequences to meet
the requirements of buffer sequences.
This proposal imposes no changes on existing implementations of [networking.ts]. It does not change anything in the standard. The proposal is precise, minimal, and allows range adapters to transform buffer sequences in optimized, compatible ways.
[Issues processing Telecon 2016-10-07]
Status set to LEWG
[2017-02-21, Jonathan comments]
The use of the term "strict aliasing" in the issue discussion is
misleading as that refers to type-based alias analysis in compilers,
but the rule for ForwardIterator
s is related to referential equality
and not strict aliasing.
[2017-02-22, Vinnie Falco comments]
We have eliminated the use of the term "strict aliasing" from the discussion.
[2017-07-10, Toronto, LEWG comments]
Status change: LEWG → Open.
Forward to LWG with the note that they may want to use "input +" instead of "bidirectional -". Unanimous yes.
[2017-07 Toronto Wednesday night issue processing]
Status to Ready
Proposed resolution:
This wording is relative to N4588.
Modify 16.2.1 [networking.ts::buffer.reqmts.mutablebuffersequence] as indicated:
An iterator type meeting the requirements for bidirectional iterators (C++Std [bidirectional.iterators]) whose value type is convertible tomutable_buffer
An iterator type whose
reference
type is convertible tomutable_buffer
, and which satisfies all the requirements for bidirectional iterators (C++Std [bidirectional.iterators]) except that:
- there is no requirement that
operator->
is provided, and- there is no requirement that
reference
be a reference type.
Modify 16.2.2 [networking.ts::buffer.reqmts.constbuffersequence] as indicated:
An iterator type meeting the requirements for bidirectional iterators (C++Std [bidirectional.iterators]) whose value type is convertible toconst_buffer
.An iterator type whose
reference
type is convertible toconst_buffer
, and which satisfies all the requirements for bidirectional iterators (C++Std [bidirectional.iterators]) except that:
- there is no requirement that
operator->
is provided, and- there is no requirement that
reference
be a reference type.