-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
This range constructor is specified in [ispanstream.cons] as:
template<class ROS> explicit basic_ispanstream(ROS&& s)
-3- Constraints:
ROSmodelsranges::borrowed_range.!convertible_to<ROS, std::span<charT>> && convertible_to<ROS, std::span<charT const>>istrue.
-4- Effects: Let
spbestd::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).