Skip to content

Commit 5565152

Browse files
committed
New issue from Ruslan Arutyunyan: "std::generate and std::ranges::generate wording is unclear for parallel algorithms"
1 parent 778339d commit 5565152

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed

xml/issue4492.xml

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
<?xml version='1.0' encoding='utf-8' standalone='no'?>
2+
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
3+
4+
<issue num="4492" status="New">
5+
<title>`std::generate` and `std::ranges::generate` wording is unclear for parallel algorithms</title>
6+
<section><sref ref="[alg.generate]"/></section>
7+
<submitter>Ruslan Arutyunyan</submitter>
8+
<date>12 Dec 2025</date>
9+
<priority>99</priority>
10+
11+
<discussion>
12+
<p>
13+
`std::generate` and `std::ranges::generate` are confusing for parallel algorithms. For both of those
14+
<i>Effects</i> says "Assigns the result of successive evaluations of `gen()` through each iterator
15+
in the range `[first, first + N)`." The word "successive" is confusing when we talk about parallelism.
16+
This wording was the preexisting one; <paper num="P3179"/> "Parallel Range Algorithms" didn't modify
17+
that, so the problem existed even before.
18+
<p/>
19+
Another problem is that there is nothing about what is allowed to do with the `Generator` template
20+
parameter type for C++17 parallel `generate`. Intel, NVIDIA, and GNU libstdc++ implementations do
21+
multiple copies of `Generator` object to maximize parallelism, while it's not technically allowed if
22+
I am reading the standard correctly. But without `Generator` being copyable we have point of contention
23+
and extra synchronization (or we put synchronization part as users' responsibility, which is also not
24+
obvious).
25+
<p/>
26+
There is no clear solution right away. We could try to fix the wording for both ranges and C++17 parallel
27+
generate but it seems like it requires extra effort because we need to at least verify the new behavior
28+
with LLVM libc++ implementation if we want to make `Generator` copyable; libc++ currently does not
29+
create per-thread copy of `gen` object. Perhaps, the best strategy for now is to remove
30+
`ranges::generate` and `ranges::generate_n` and return them back in C++29 time frame when we figure
31+
out the proper fix.
32+
</p>
33+
</discussion>
34+
35+
<resolution>
36+
<p>
37+
This wording is relative to <paper num="N5032"/>.
38+
</p>
39+
40+
<ol>
41+
<li><p>Modify <sref ref="[algorithm.syn]"/>, header <tt>&lt;algorithm&gt;</tt> synopsis, as indicated:</p>
42+
43+
<blockquote>
44+
<pre>
45+
[&hellip;]
46+
<i>// <sref ref="[alg.generate]"/>, generate</i>
47+
template&lt;class ForwardIterator, class Generator&gt;
48+
constexpr void generate(ForwardIterator first, ForwardIterator last,
49+
Generator gen);
50+
template&lt;class ExecutionPolicy, class ForwardIterator, class Generator&gt;
51+
void generate(ExecutionPolicy&amp;&amp; exec, <i>// freestanding-deleted, see <sref ref="[algorithms.parallel.overloads]"/></i>
52+
ForwardIterator first, ForwardIterator last,
53+
Generator gen);
54+
template&lt;class OutputIterator, class Size, class Generator&gt;
55+
constexpr OutputIterator generate_n(OutputIterator first, Size n, Generator gen);
56+
template&lt;class ExecutionPolicy, class ForwardIterator, class Size, class Generator&gt;
57+
ForwardIterator generate_n(ExecutionPolicy&amp;&amp; exec, <i>// freestanding-deleted, see <sref ref="[algorithms.parallel.overloads]"/></i>
58+
ForwardIterator first, Size n, Generator gen);
59+
60+
namespace ranges {
61+
template&lt;input_or_output_iterator O, sentinel_for&lt;O&gt; S, copy_constructible F&gt;
62+
requires invocable&lt;F&amp;&gt; &amp; indirectly_writable&lt;O, invoke_result_t&lt;F&amp;&gt;&gt;
63+
constexpr O generate(O first, S last, F gen);
64+
template&lt;class R, copy_constructible F&gt;
65+
requires invocable&lt;F&amp;&gt; &amp; output_range&lt;R, invoke_result_t&lt;F&amp;&gt;&gt;
66+
constexpr borrowed_iterator_t&lt;R&gt; generate(R&amp;&amp; r, F gen);
67+
template&lt;input_or_output_iterator O, copy_constructible F&gt;
68+
requires invocable&lt;F&amp;&gt; &amp; indirectly_writable&lt;O, invoke_result_t&lt;F&amp;&gt;&gt;
69+
constexpr O generate_n(O first, iter_difference_t&lt;O&gt; n, F gen);
70+
<del>template&lt;<i>execution-policy</i> Ep, random_access_iterator O, sized_sentinel_for&lt;O&gt; S,
71+
copy_constructible F&gt;
72+
requires invocable&lt;F&amp;&gt; &amp; indirectly_writable&lt;O, invoke_result_t&lt;F&amp;&gt;&gt;
73+
O generate(Ep&amp;&amp; exec, O first, S last, F gen); <i>// freestanding-deleted</i>
74+
template&lt;<i>execution-policy</i> Ep, <i>sized-random-access-range</i> R, copy_constructible F&gt;
75+
requires invocable&lt;F&amp;&gt; &amp; indirectly_writable&lt;iterator_t&lt;R&gt;, invoke_result_t&lt;F&amp;&gt;&gt;
76+
borrowed_iterator_t&lt;R&gt; generate(Ep&amp;&amp; exec, R&amp;&amp; r, F gen); <i>// freestanding-deleted</i>
77+
template&lt;<i>execution-policy</i> Ep, random_access_iterator O, copy_constructible F&gt;
78+
requires invocable&lt;F&amp;&gt; &amp; indirectly_writable&lt;O, invoke_result_t&lt;F&amp;&gt;&gt;
79+
O generate_n(Ep&amp;&amp; exec, O first, iter_difference_t&lt;O&gt; n, F gen); <i>// freestanding-deleted</i></del>
80+
}
81+
[&hellip;]
82+
</pre>
83+
</blockquote>
84+
</li>
85+
86+
<li><p>Modify <sref ref="[alg.generate]"/> as indicated:</p>
87+
88+
<blockquote>
89+
<pre>
90+
template&lt;class ForwardIterator, class Generator&gt;
91+
constexpr void generate(ForwardIterator first, ForwardIterator last,
92+
Generator gen);
93+
template&lt;class ExecutionPolicy, class ForwardIterator, class Generator&gt;
94+
void generate(ExecutionPolicy&amp;&amp; exec,
95+
ForwardIterator first, ForwardIterator last,
96+
Generator gen);
97+
98+
template&lt;class OutputIterator, class Size, class Generator&gt;
99+
constexpr OutputIterator generate_n(OutputIterator first, Size n, Generator gen);
100+
template&lt;class ExecutionPolicy, class ForwardIterator, class Size, class Generator&gt;
101+
ForwardIterator generate_n(ExecutionPolicy&amp;&amp; exec,
102+
ForwardIterator first, Size n, Generator gen);
103+
104+
template&lt;input_or_output_iterator O, sentinel_for&lt;O&gt; S, copy_constructible F&gt;
105+
requires invocable&lt;F&amp;&gt; &amp; indirectly_writable&lt;O, invoke_result_t&lt;F&amp;&gt;&gt;
106+
constexpr O ranges::generate(O first, S last, F gen);
107+
template&lt;class R, copy_constructible F&gt;
108+
requires invocable&lt;F&amp;&gt; &amp; output_range&lt;R, invoke_result_t&lt;F&amp;&gt;&gt;
109+
constexpr borrowed_iterator_t&lt;R&gt; ranges::generate(R&amp;&amp; r, F gen);
110+
template&lt;input_or_output_iterator O, copy_constructible F&gt;
111+
requires invocable&lt;F&amp;&gt; &amp; indirectly_writable&lt;O, invoke_result_t&lt;F&amp;&gt;&gt;
112+
constexpr O ranges::generate_n(O first, iter_difference_t&lt;O&gt; n, F gen);
113+
<del>template&lt;<i>execution-policy</i> Ep, random_access_iterator O, sized_sentinel_for&lt;O&gt; S,
114+
copy_constructible F&gt;
115+
requires invocable&lt;F&amp;&gt; &amp; indirectly_writable&lt;O, invoke_result_t&lt;F&amp;&gt;&gt;
116+
O ranges::generate(Ep&amp;&amp; exec, O first, S last, F gen);
117+
template&lt;<i>execution-policy</i> Ep, <i>sized-random-access-range</i> R, copy_constructible F&gt;
118+
requires invocable&lt;F&amp;&gt; &amp; indirectly_writable&lt;iterator_t&lt;R&gt;, invoke_result_t&lt;F&amp;&gt;&gt;
119+
borrowed_iterator_t&lt;R&gt; ranges::generate(Ep&amp;&amp; exec, R&amp;&amp; r, F gen);
120+
template&lt;<i>execution-policy</i> Ep, random_access_iterator O, copy_constructible F&gt;
121+
requires invocable&lt;F&amp;&gt; &amp; indirectly_writable&lt;O, invoke_result_t&lt;F&amp;&gt;&gt;
122+
O ranges::generate_n(Ep&amp;&amp; exec, O first, iter_difference_t&lt;O&gt; n, F gen);</del>
123+
</pre>
124+
<blockquote>
125+
<p>
126+
-1- Let <tt><i>N</i></tt> be `max(0, n)` for the `generate_n` algorithms, and `last - first` for the `generate` algorithms.
127+
<p/>
128+
[&hellip;]
129+
</p>
130+
</blockquote>
131+
</blockquote>
132+
</li>
133+
134+
</ol>
135+
136+
</resolution>
137+
138+
</issue>

0 commit comments

Comments
 (0)