This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
std::span<volatile T, E> is made ill-formed by P2278R4 when T is a normal class typeSection: 23.7.2.2.1 [span.overview] Status: New Submitter: Jiang An Opened: 2022-11-06 Last modified: 2025-03-22
Priority: 2
View all other issues in [span.overview].
View all issues with New status.
Discussion:
This issue is discovered when implementing the
span part of P2278R4 in MSVC STL.
const_iterator member type to std::span, which required its
iterator type to model std::input_iterator (same for const_reverse_iterator and
reverse_iterator).
However, when element_type is volatile T and T is a class type, the iterator
type generally fails to satisfy input_iterator, because:
input_iterator<iterator> requires indirectly_readable<iterator>;
indirectly_readable<iterator> requires common_reference_with<iterator_reference_t<iterator>&&,
iterator_rvalue_reference_t<iterator>&&>, that is
common_reference_with<volatile T&, volatile T&&>;
common_reference_t<volatile T&, volatile T&&> is T (which is problematic),
and thus common_reference_with<volatile T&, volatile T&&> requires both
convertible_to<volatile T&, T> and convertible_to<volatile T&&, T>;
However, the class type T generally doesn't have constructors from volatile T or
const volatile T glvalues, and thus neither convertible_to<volatile T&, T> and
convertible_to<volatile T&&, T> is satisfied.
Ideally, span should not require any form of construction of element_type. Although usages of
class types provided by the standard library via volatile glvalues are generally not supported, I think
span<volatile T, E> is still useful for some user-defined class type T, and thus shouldn't be forbidden.
[Kona 2022-11-12; Set priority to 2]
[2025-03-22; Jiang An comments and provides wording]
The proposed resolution relaxes the input_iterator concept (which in turn relaxes stronger iterator concepts)
and extends iter_const_reference_t and the exposition only iter-const-rvalue-reference-t
aliases. Another approach can be just relaxing the indirectly_readable concept, but its impact may be larger
than expected.
Proposed resolution:
This wording is relative to N5008.
Modify 24.2 [iterator.synopsis], header <iterator> synopsis, as indicated:
[…] // 24.3.4.9 [iterator.concept.input], concept input_iterator template<class I> concept deref-to-value-t = see below; // freestanding template<class I> concept weakly-indirectly-readable = see below; // freestanding template<class I> concept input_iterator = see below; // freestanding […] // 24.5.3.2 [const.iterators.alias], alias templates template<indirectly_readableweakly-indirectly-readable I> using iter_const_reference_t = see below;
Modify 24.3.4.9 [iterator.concept.input], concept input_iterator synopsis, as indicated:
template<class I>
concept deref-to-value-t-impl = // exposition only
same_as<remove_cvref_t<iter_reference_t<I>>, iter_value_t<I>> &&
is_object_v<iter_value_t<I>>;
template<class I>
concept deref-to-value-t = // exposition only
deref-to-value-t-impl<remove_cvref_t<I>>;
template<class I>
concept weakly-indirectly-readable = // exposition only
deref-to-value-t<I> ||
indirectly_readable<I>;
template<class I>
concept input_iterator =
input_or_output_iterator<I> &&
indirectly_readableweakly-indirectly-readable<I> &&
requires { typename ITER_CONCEPT(I); } &&
derived_from<ITER_CONCEPT(I), input_iterator_tag>;
Modify 24.5.3.2 [const.iterators.alias] as indicated:
template<class T> using ref-add-const-t = see below;-?- Result: If
is_lvalue_reference_v<T>istrue,const remove_reference_t<T>&. Otherwise, ifis_rvalue_reference_v<T>istrue,const remove_reference_t<T>&&. Otherwise,T.template<indirectly_readableweakly-indirectly-readable It> using iter_const_reference_t = see below;common_reference_t<const iter_value_t<It>&&, iter_reference_t<It>>;-?- Result: If
Itmodelsderef-to-value-t,ref-add-const-t<iter_reference_t<It>>. Otherwise,common_reference_t<const iter_value_t<It>&&, iter_reference_t<It>>.
[Drafting note: The simple
deref-to-value-tcase should be detected first, which avoids unnecessary instantiations and IFNDR-ness.]
Modify 24.5.3.3 [const.iterators.iterator] as indicated:
[…] template<indirectly_readableweakly-indirectly-readable I> using iter-const-rvalue-reference-t = // exposition only common_reference_t<const iter_value_t<I>&&, iter_rvalue_reference_t<I>>; […]