|
| 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<int> 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<int, float> fm; // iterator value_type is pair<int, float> |
| 33 | +std::map m1(fm.begin(), fm.end()); // OK, deduces std::map<int, float> |
| 34 | + |
| 35 | +auto tv = fm | std::views::transform(std::identity{}); // iterator value value_type is pair<int const&, float const&> |
| 36 | +std::map m3(tv.begin(), tv.end()); // <span style="color:red;font-weight:bolder">Ill-formed, deduces std::map<int const&, float&></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<int const, float const> tp[2]; |
| 53 | +std::map m(std::begin(tp), std::end(tp)); // Was std::map<int, float const>, now std::map<int, float> |
| 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<class InputIterator> |
| 65 | + using <i>iter-value-type</i> = |
| 66 | + typename iterator_traits<InputIterator>::value_type; // <i>exposition only</i> |
| 67 | + |
| 68 | +template<class InputIterator> |
| 69 | + using <i>iter-key-type</i> = <del>remove_const_t</del><ins>remove_cvref_t</ins>< |
| 70 | + tuple_element_t<0, <i>iter-value-type</i><InputIterator>>>; // <i>exposition only</i> |
| 71 | + |
| 72 | +template<class InputIterator> |
| 73 | + using <i>iter-mapped-type</i> = <ins>remove_cvref_t<</ins> |
| 74 | + tuple_element_t<1, <i>iter-value-type</i><InputIterator>><ins>></ins>; // <i>exposition only</i> |
| 75 | + |
| 76 | +template<class InputIterator> |
| 77 | + using <i>iter-to-alloc-type</i> = pair< |
| 78 | + add_const_t< |
| 79 | + <del>tuple_element_t<0, <i>iter-value-type</i><InputIterator>></del> |
| 80 | + <ins><i>iter-key-type</i><InputIterator></ins> |
| 81 | + >, |
| 82 | + <del>tuple_element_t<1, <i>iter-value-type</i><InputIterator>></del> |
| 83 | + <ins><i>iter-mapped-type</i><InputIterator></ins> |
| 84 | + >; // <i>exposition only</i> |
| 85 | + |
| 86 | +template<ranges::input_range Range> |
| 87 | + using <i>range-key-type</i> = |
| 88 | + <del>remove_const_t<typename ranges::range_value_t<Range>::first_type></del> |
| 89 | + <ins>remove_cvref_t<tuple_element_t<0, ranges::range_value_t<Range>>></ins>; // <i>exposition only</i> |
| 90 | + |
| 91 | +template<ranges::input_range Range> |
| 92 | + using <i>range-mapped-type</i> = |
| 93 | + <del>typename ranges::range_value_t<Range>::second_type</del> |
| 94 | + <ins>remove_cvref_t<tuple_element_t<1, ranges::range_value_t<Range>>></ins>; // <i>exposition only</i> |
| 95 | + |
| 96 | +template<ranges::input_range Range> |
| 97 | + using <i>range-to-alloc-type</i> = |
| 98 | + pair<add_const_t< |
| 99 | + <del>typename ranges::range_value_t<Range>::first_type</del> |
| 100 | + <ins><i>range-key-type</i><Range></ins> |
| 101 | + >, |
| 102 | + <del>typename ranges::range_value_t<Range>::second_type</del> |
| 103 | + <ins><i>range-mapped-type</i><Range></ins> |
| 104 | + >; // <i>exposition only</i> |
| 105 | +</pre> |
| 106 | +</blockquote> |
| 107 | +</li> |
| 108 | +</ol> |
| 109 | +</resolution> |
| 110 | + |
| 111 | +</issue> |
0 commit comments