From d79f5b7a6eea858805a59437b02d14b4562a8000 Mon Sep 17 00:00:00 2001
From: github-actions 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. Section: 26.7.17.3 [range.split.iterator] Status: New
+ Submitter: Barry Revzin Opened: 2023-11-19 Last modified: 2023-11-25 Priority: Not Prioritized
+ View all issues with New status. Discussion:
+Consider the following example (which uses fmt::println instead of std::println,
+but they do the same thing in C++23):
+
+The output of this program (as specified today) is
+
+The principle set out in LWG 3478 is that splitting a sequence containing N
+delimiters should lead to N+1 subranges. That principle was broken if the N-th
+delimiter was at the end of the sequence, which was fixed by P2210.
+
+4017. Behavior of std::views::split on an empty range
+
+
+#include <iostream>
+#include <string>
+#include <ranges>
+#include <fmt/ranges.h>
+
+int main()
+{
+ fmt::println("{}", std::views::split(std::string(" x "), ' '));
+ fmt::println("{}", std::views::split(std::string(" "), ' '));
+ fmt::println("{}", std::views::split(std::string("x"), ' '));
+ fmt::println("{}", std::views::split(std::string(""), ' '));
+}
+
+
+[[], ['x'], []]
+[[], []]
+[['x']]
+[]
+
Proposed resolution:
++This wording is relative to N4964. +
+ +Modify 26.7.17.3 [range.split.iterator] as indicated:
+ ++++constexpr iterator(split_view& parent, iterator_t<V> current, subrange<iterator_t<V>> next); +++++-1- Effects: Initializes parent_ with addressof(parent), cur_ with +std::move(current),
+andnext_ with std::move(next), and +trailing_empty_ with cur_ == next_.begin(). +
Revised 2023-11-24 at 17:56:34 UTC
+Revised 2023-11-25 at 13:21:24 UTC
Reference ISO/IEC IS 14882:2020(E)
Also see:
@@ -182,15 +182,15 @@Section: 26.7.17.3 [range.split.iterator] Status: New + Submitter: Barry Revzin Opened: 2023-11-19 Last modified: 2023-11-25
+Priority: Not Prioritized +
+View all issues with New status.
+Discussion:
++Consider the following example (which uses fmt::println instead of std::println, +but they do the same thing in C++23): +
+++#include <iostream> +#include <string> +#include <ranges> +#include <fmt/ranges.h> + +int main() +{ + fmt::println("{}", std::views::split(std::string(" x "), ' ')); + fmt::println("{}", std::views::split(std::string(" "), ' ')); + fmt::println("{}", std::views::split(std::string("x"), ' ')); + fmt::println("{}", std::views::split(std::string(""), ' ')); +} +
+The output of this program (as specified today) is +
+++[[], ['x'], []] +[[], []] +[['x']] +[] +
+The principle set out in LWG 3478 is that splitting a sequence containing N +delimiters should lead to N+1 subranges. That principle was broken if the N-th +delimiter was at the end of the sequence, which was fixed by P2210. +
+However, the principle is still broken if the sequence contains zero delimiters. A non-empty sequence +will split into one range, but an empty sequence will split into zero ranges. That last line is incorrect +— splitting an empty range on a delimiter should yield a range of an empty range — not +simply an empty range. + +Proposed Resolution: Currently, split_view::iterator's constructor unconditionally initializes +trailing_empty_ to false. Instead, change 26.7.17.3 [range.split.iterator]/1 +to initialize trailing_empty_ to cur_ == next_.begin() (i.e. +trailing_empty_ is typically false, but if we're empty on initialization then we +have to have a trailing empty range). + +The following demo shows my implementation from P2210, adjusted to fix this: +godbolt.org/z/axWb64j9f + + + +Proposed resolution:
++This wording is relative to N4964. +
+ +Modify 26.7.17.3 [range.split.iterator] as indicated:
+ ++++constexpr iterator(split_view& parent, iterator_t<V> current, subrange<iterator_t<V>> next); +++++-1- Effects: Initializes parent_ with addressof(parent), cur_ with +std::move(current),
+andnext_ with std::move(next), and +trailing_empty_ with cur_ == next_.begin(). +