Skip to content

Commit 553b5c9

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

File tree

1 file changed

+111
-0
lines changed

1 file changed

+111
-0
lines changed

xml/issue4180.xml

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
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` (<sref ref="[deque.modifiers]"/>), `list` (<sref ref="[list.modifiers]"/>),
19+
`vector` (<sref ref="[vector.modifiers]"/>), `containers` (<sref ref="[sequence.reqmts]"/> p19),
20+
`associative containers` (<sref ref="[associative.reqmts.general]"/> p47),
21+
`unordered containers` (<sref ref="[unord.req.general]"/> p78), `priority_queue` (<sref ref="[priqueue.members]"/> p5),
22+
`optional` (<sref ref="[optional.assign]"/> p29).
23+
<p/>
24+
Constraints on `emplace`: `flat_map` (<sref ref="[flat.map.modifiers]"/> p1),
25+
`flat_multiset` (<sref ref="[flat.multiset.modifiers]"/> p1), `any` (<sref ref="[any.modifiers]"/> p1),
26+
`expected` (<sref ref="[expected.object.assign]"/> p16), `variant` (<sref ref="[variant.mod]"/> p1).
27+
<p/>
28+
I believe a <i>Constraints</i> element was accidentally copy-pasted from the spec of <tt>flat_map::insert(P&amp;&amp;)</tt>
29+
&mdash; which does need the constraint because it's part of `insert`'s large overload set &mdash; to
30+
`flat_map::emplace`, and then from there to `flat_multiset::emplace`. The constraint is already (correctly) absent
31+
`from flat_set::emplace`.
32+
<p/>
33+
While we're touching this paragraph, also resolve the vague word "initializes" to "direct-non-list-initializes."
34+
Editorially, <tt>pair&lt;&hellip;&gt;</tt> is a verbose way to spell the `value_type` of a `flat_map`; we should
35+
be consistent and just say `value_type`.
36+
</p>
37+
</discussion>
38+
39+
<resolution>
40+
<p>
41+
This wording is relative to <paper num="N4993"/>.
42+
</p>
43+
44+
<blockquote class="note">
45+
<p>
46+
[<i>Drafting note</i>: <sref ref="[flat.set.modifiers]"/> is already OK as far as this issue is concerned:
47+
it has no wording for `emplace`.
48+
<p/>
49+
[flat.multimap.modifiers] is already OK ditto: it does not exist. ]
50+
</p>
51+
</blockquote>
52+
53+
<ol>
54+
<li><p>Modify <sref ref="[flat.multiset.modifiers]"/> as indicated:</p>
55+
56+
<blockquote>
57+
<pre>
58+
template&lt;class... Args&gt; iterator emplace(Args&amp;&amp;... args);
59+
</pre>
60+
<blockquote>
61+
<p>
62+
-1- <i><ins>Mandates</ins><del>Constraints</del></i>: <tt>is_constructible_v&lt;value_type, Args...&gt;</tt> is <tt>true</tt>.
63+
<p/>
64+
-2- <i>Effects</i>: First, <ins>direct-non-list-</ins>initializes an object `t` of type `value_type` with
65+
<tt>std::forward&lt;Args&gt;(args)...</tt>, then inserts `t` as if by:
66+
</p>
67+
<blockquote><pre>
68+
auto it = ranges::upper_bound(c, t, compare);
69+
c.insert(it, std::move(t));
70+
</pre></blockquote>
71+
<p>
72+
-3- <i>Returns</i>: An iterator that points to the inserted element.
73+
</p>
74+
</blockquote>
75+
</blockquote>
76+
77+
</li>
78+
79+
<li><p>Modify <sref ref="[flat.map.modifiers]"/> as indicated:</p>
80+
81+
<blockquote>
82+
<pre>
83+
template&lt;class... Args&gt; pair&lt;iterator, bool&gt; emplace(Args&amp;&amp;... args);
84+
</pre>
85+
<blockquote>
86+
<p>
87+
-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>
88+
is <tt>true</tt>.
89+
<p/>
90+
-2- <i>Effects</i>: <ins>First, direct-non-list-i</ins><del>I</del>nitializes an object `t` of type
91+
<tt><ins>value_type</ins><del>pair&lt;key_type, mapped_type&gt;</del></tt> with <tt>std::forward&lt;Args&gt;(args)...</tt>;
92+
if the map already contains an element whose key is equivalent to `t.first`, `*this` is unchanged. Otherwise, equivalent to:
93+
</p>
94+
<blockquote><pre>
95+
auto key_it = ranges::upper_bound(c.keys, t.first, compare);
96+
auto value_it = c.values.begin() + distance(c.keys.begin(), key_it);
97+
c.keys.insert(key_it, std::move(t.first));
98+
c.values.insert(value_it, std::move(t.second));
99+
</pre></blockquote>
100+
<p>
101+
-3- <i>Returns</i>: The `bool` component of the returned pair is `true` if and only if the insertion took place, and
102+
the iterator component of the pair points to the element with key equivalent to `t.first`.
103+
</p>
104+
</blockquote>
105+
</blockquote>
106+
107+
</li>
108+
</ol>
109+
</resolution>
110+
111+
</issue>

0 commit comments

Comments
 (0)