This range constructor is specified in [ispanstream.cons] as:
template<class ROS> explicit basic_ispanstream(ROS&& s)
-3- Constraints: ROS models ranges::borrowed_range. !convertible_to<ROS, std::span<charT>> && convertible_to<ROS, std::span<charT const>> is true.
-4- Effects: Let sp be std::span<const charT>(std::forward<ROS>(s)). Equivalent to:
basic_ispanstream(std::span<charT>(const_cast<charT*>(sp.data()), sp.size()))
Here, only std::span<const charT>(std::forward<ROS>(s)) is required, but MSVC always constructs span via std::span<const charT>(ranges:: data(s)), ranges::size(s)), which is not always well-formed (for example, when s is not a sized_range or contiguous_range):
#include <spanstream>
struct R {
int* begin();
std::unreachable_sentinel_t end();
operator std::span<const int>() const;
};
int main() {
R r{};
std::basic_ispanstream<int> is{r}; // error
is.span(r); // error
}
https://godbolt.org/z/Trv8d8qd3
The above example seems contrived, but libstdc++ accepts it as the standard guarantees it. (Whether this is worthy of LWG may be arguable).
This range constructor is specified in [ispanstream.cons] as:
Here, only
std::span<const charT>(std::forward<ROS>(s))is required, but MSVC always constructsspanviastd::span<const charT>(ranges:: data(s)), ranges::size(s)), which is not always well-formed (for example, whensis not asized_rangeorcontiguous_range):https://godbolt.org/z/Trv8d8qd3
The above example seems contrived, but libstdc++ accepts it as the standard guarantees it. (Whether this is worthy of LWG may be arguable).