Skip to content

Commit 5704dfd

Browse files
committed
New issue from Arthur: "Inconsistent constraints on flat_foo::emplace"
1 parent 04cd4c8 commit 5704dfd

File tree

1 file changed

+106
-0
lines changed

1 file changed

+106
-0
lines changed

xml/issue4180.xml

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?xml version='1.0' encoding='utf-8' standalone='no'?>
2+
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
3+
4+
<issue num="4180" status="New">
5+
<title>Inconsistent constraints on <tt>flat_<i>foo</i>::emplace</tt></title>
6+
<section><sref ref="[flat.multiset.modifiers]"/><sref ref="[flat.map.modifiers]"/></section>
7+
<submitter>Arthur O'Dwyer</submitter>
8+
<date>09 Dec 2024</date>
9+
<priority>99</priority>
10+
11+
<discussion>
12+
<p>
13+
The usual pattern in <sref ref="[containers]"/> is that `x.emplace(args...)` has a precondition
14+
(<sref ref="[sequence.reqmts]"/> p20, <sref ref="[associative.reqmts.general]"/> p48) but no
15+
<i>Constraints</i> element. That is, `emplace` is not SFINAE-friendly. And it has only the one overload,
16+
so it doesn't need a constraint for purposes of overload resolution.
17+
<p/>
18+
No Constraints on `emplace`: `deque`, `list`, `vector`, `containers`, `associative containers`, `unordered containers`,
19+
`priority_queue`, `optional`.
20+
<p/>
21+
Constraints on `emplace`: `flat_map`, `flat_multiset`, `any`, `expected`, `variant`.
22+
<p/>
23+
I believe a <i>Constraints</i> element was accidentally copy-pasted from the spec of <tt>flat_map::insert(P&amp;&amp;)</tt>
24+
&mdash; which does need the constraint because it's part of `insert`'s large overload set &mdash; to
25+
`flat_map::emplace`, and then from there to `flat_multiset::emplace`. The constraint is already (correctly) absent
26+
`from flat_set::emplace`.
27+
<p/>
28+
While we're touching this paragraph, also resolve the vague word "initializes" to "direct-non-list-initializes."
29+
Editorially, <tt>pair&lt;&hellip;&gt;</tt> is a verbose way to spell the `value_type` of a `flat_map`; we should
30+
be consistent and just say `value_type`.
31+
</p>
32+
</discussion>
33+
34+
<resolution>
35+
<p>
36+
This wording is relative to <paper num="N4993"/>.
37+
</p>
38+
39+
<blockquote class="note">
40+
<p>
41+
[<i>Drafting note</i>: <sref ref="[flat.set.modifiers]"/> is already OK as far as this issue is concerned:
42+
it has no wording for `emplace`.
43+
<p/>
44+
[flat.multimap.modifiers] is already OK ditto: it does not exist. ]
45+
</p>
46+
</blockquote>
47+
48+
<ol>
49+
<li><p>Modify <sref ref="[flat.multiset.modifiers]"/> as indicated:</p>
50+
51+
<blockquote>
52+
<pre>
53+
template&lt;class... Args&gt; iterator emplace(Args&amp;&amp;... args);
54+
</pre>
55+
<blockquote>
56+
<p>
57+
-1- <i><ins>Mandates</ins><del>Constraints</del></i>: <tt>is_constructible_v&lt;value_type, Args...&gt;</tt> is <tt>true</tt>.
58+
<p/>
59+
-2- <i>Effects</i>: First, <ins>direct-non-list-</ins>initializes an object `t` of type `value_type` with
60+
<tt>std::forward&lt;Args&gt;(args)...</tt>, then inserts `t` as if by:
61+
</p>
62+
<blockquote><pre>
63+
auto it = ranges::upper_bound(c, t, compare);
64+
c.insert(it, std::move(t));
65+
</pre></blockquote>
66+
<p>
67+
-3- <i>Returns</i>: An iterator that points to the inserted element.
68+
</p>
69+
</blockquote>
70+
</blockquote>
71+
72+
</li>
73+
74+
<li><p>Modify <sref ref="[flat.map.modifiers]"/> as indicated:</p>
75+
76+
<blockquote>
77+
<pre>
78+
template&lt;class... Args&gt; pair&lt;iterator, bool&gt; emplace(Args&amp;&amp;... args);
79+
</pre>
80+
<blockquote>
81+
<p>
82+
-1- <i><ins>Mandates</ins><del>Constraints</del></i>: <tt>is_constructible_v&lt;<ins>value_type</ins><del>pair&lt;key_type, mapped_type&gt;</del>, Args...&gt;</tt>
83+
is <tt>true</tt>.
84+
<p/>
85+
-2- <i>Effects</i>: <ins>First, direct-non-list-i</ins><del>I</del>nitializes an object `t` of type
86+
<tt><ins>value_type</ins><del>pair&lt;key_type, mapped_type&gt;</del></tt> with <tt>std::forward&lt;Args&gt;(args)...</tt>;
87+
if the map already contains an element whose key is equivalent to `t.first`, `*this` is unchanged. Otherwise, equivalent to:
88+
</p>
89+
<blockquote><pre>
90+
auto key_it = ranges::upper_bound(c.keys, t.first, compare);
91+
auto value_it = c.values.begin() + distance(c.keys.begin(), key_it);
92+
c.keys.insert(key_it, std::move(t.first));
93+
c.values.insert(value_it, std::move(t.second));
94+
</pre></blockquote>
95+
<p>
96+
-3- <i>Returns</i>: The `bool` component of the returned pair is `true` if and only if the insertion took place, and
97+
the iterator component of the pair points to the element with key equivalent to `t.first`.
98+
</p>
99+
</blockquote>
100+
</blockquote>
101+
102+
</li>
103+
</ol>
104+
</resolution>
105+
106+
</issue>

0 commit comments

Comments
 (0)