Skip to content

Commit c268239

Browse files
committed
New issue from Tomasz: "Deduction guides for maps are mishandling tuples and references"
1 parent 750fe0f commit c268239

File tree

1 file changed

+111
-0
lines changed

1 file changed

+111
-0
lines changed

xml/issue4223.xml

Lines changed: 111 additions & 0 deletions
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="4223" status="New">
5+
<title>Deduction guides for maps are mishandling tuples and references</title>
6+
<section>
7+
<sref ref="[associative.general]"/>
8+
</section>
9+
<submitter>Tomasz Kaminski</submitter>
10+
<date>14 Mar 2025</date>
11+
<priority>99</priority>
12+
13+
<discussion>
14+
<p>
15+
The `from_range` deduction guide for maps currently do not handle ranges of tuple of two elements:
16+
</p>
17+
<blockquote><pre>
18+
std::vector&lt;int&gt; v;
19+
auto zv = std::views::zip(v, v);
20+
std::map m4(std::from_range, zv); // <span style="color:red;font-weight:bolder">Ill-formed, no-deduction guide</span>
21+
</pre></blockquote>
22+
<p>
23+
This seems to be result of merge conflict between <paper num="P2165"/> (Compatibility between tuple, pair and tuple-like objects)
24+
and <paper num="P1206R4"/> (Conversions from ranges to containers): The helper <tt><i>range-key-type</i></tt> and
25+
<tt><i>range-mapped-type</i></tt> aliases introduced by the later use the old formulation of `::first_type`,
26+
`::second::type` instead of `tuple_element`.
27+
<p/>
28+
Furthermore, both iterator and range deduction guides do not correctly handle iterators with a pair of references as
29+
value types, and deduce key or value type as reference, which is ill-formed:
30+
</p>
31+
<blockquote><pre>
32+
std::flat_map&lt;int, float&gt; fm; // iterator value_type is pair&lt;int, float&gt;
33+
std::map m1(fm.begin(), fm.end()); // OK, deduces std::map&lt;int, float&gt;
34+
35+
auto tv = fm | std::views::transform(std::identity{}); // iterator value value_type is pair&lt;int const&amp;, float const&amp;&gt;
36+
std::map m3(tv.begin(), tv.end()); // <span style="color:red;font-weight:bolder">Ill-formed, deduces std::map&lt;int const&amp;, float&amp;&gt;</span>
37+
</pre></blockquote>
38+
39+
</discussion>
40+
41+
<resolution>
42+
<p>
43+
This wording is relative to <paper num="N5001"/>.
44+
</p>
45+
46+
<blockquote class="note">
47+
<p>
48+
[<i>Drafting note</i>: The proposed change also strips `const` from the value type of the `map`,
49+
changing the behavior of previously working code:
50+
</p>
51+
<blockquote><pre>
52+
std::pair&lt;int const, float const&gt; tp[2];
53+
std::map m(std::begin(tp), std::end(tp)); // Was std::map&lt;int, float const&gt;, now std::map&lt;int, float&gt;
54+
</pre></blockquote>
55+
]
56+
</blockquote>
57+
58+
<ol>
59+
60+
<li><p>Modify <sref ref="[associative.general]"/> as indicated:</p>
61+
62+
<blockquote>
63+
<pre>
64+
template&lt;class InputIterator&gt;
65+
using <i>iter-value-type</i> =
66+
typename iterator_traits&lt;InputIterator&gt;::value_type; // <i>exposition only</i>
67+
68+
template&lt;class InputIterator&gt;
69+
using <i>iter-key-type</i> = <del>remove_const_t</del><ins>remove_cvref_t</ins>&lt;
70+
tuple_element_t&lt;0, <i>iter-value-type</i>&lt;InputIterator&gt;&gt;&gt;; // <i>exposition only</i>
71+
72+
template&lt;class InputIterator&gt;
73+
using <i>iter-mapped-type</i> = <ins>remove_cvref_t&lt;</ins>
74+
tuple_element_t&lt;1, <i>iter-value-type</i>&lt;InputIterator&gt;&gt;<ins>&gt;</ins>; // <i>exposition only</i>
75+
76+
template&lt;class InputIterator&gt;
77+
using <i>iter-to-alloc-type</i> = pair&lt;
78+
add_const_t&lt;
79+
<del>tuple_element_t&lt;0, <i>iter-value-type</i>&lt;InputIterator&gt;&gt;</del>
80+
<ins><i>iter-key-type</i>&lt;InputIterator&gt;</ins>
81+
&gt;,
82+
<del>tuple_element_t&lt;1, <i>iter-value-type</i>&lt;InputIterator&gt;&gt;</del>
83+
<ins><i>iter-mapped-type</i>&lt;InputIterator&gt;</ins>
84+
&gt;; // <i>exposition only</i>
85+
86+
template&lt;ranges::input_range Range&gt;
87+
using <i>range-key-type</i> =
88+
<del>remove_const_t&lt;typename ranges::range_value_t&lt;Range&gt;::first_type&gt;</del>
89+
<ins>remove_cvref_t&lt;tuple_element_t&lt;0, ranges::range_value_t&lt;Range&gt;&gt;&gt;</ins>; // <i>exposition only</i>
90+
91+
template&lt;ranges::input_range Range&gt;
92+
using <i>range-mapped-type</i> =
93+
<del>typename ranges::range_value_t&lt;Range&gt;::second_type</del>
94+
<ins>remove_cvref_t&lt;tuple_element_t&lt;1, ranges::range_value_t&lt;Range&gt;&gt;&gt;</ins>; // <i>exposition only</i>
95+
96+
template&lt;ranges::input_range Range&gt;
97+
using <i>range-to-alloc-type</i> =
98+
pair&lt;add_const_t&lt;
99+
<del>typename ranges::range_value_t&lt;Range&gt;::first_type</del>
100+
<ins><i>range-key-type</i>&lt;Range&gt;</ins>
101+
&gt;,
102+
<del>typename ranges::range_value_t&lt;Range&gt;::second_type</del>
103+
<ins><i>range-mapped-type</i>&lt;Range&gt;</ins>
104+
&gt;; // <i>exposition only</i>
105+
</pre>
106+
</blockquote>
107+
</li>
108+
</ol>
109+
</resolution>
110+
111+
</issue>

0 commit comments

Comments
 (0)