|
| 1 | +<?xml version='1.0' encoding='utf-8' standalone='no'?> |
| 2 | +<!DOCTYPE issue SYSTEM "lwg-issue.dtd"> |
| 3 | + |
| 4 | +<issue num="4472" status="New"> |
| 5 | +<title><tt>std::atomic_ref<const T></tt> can be constructed from temporaries</title> |
| 6 | +<section><sref ref="[atomics.ref.generic]"/></section> |
| 7 | +<submitter>Jiang An</submitter> |
| 8 | +<date>11 Nov 2025</date> |
| 9 | +<priority>99</priority> |
| 10 | + |
| 11 | +<discussion> |
| 12 | +<p> |
| 13 | +<tt>std::atomic_ref<T></tt> has a constructor taking <tt>T&</tt>, so when `T` is a `const` |
| 14 | +but not `volatile` object type, the constructor parameter can be bound to a temporary expression, |
| 15 | +which doesn't seem to make sense. Even after <paper num="P3860R1"/>, explicitly constructing |
| 16 | +<tt>std::atomic_ref<const T></tt> from <tt>std::atomic_ref<volatile T></tt> can be |
| 17 | +well-formed with the undesired semantics when it is well-formed to instantiate |
| 18 | +<tt>std::atomic_ref<volatile T></tt> and its operator `T` conversion function, because the |
| 19 | +construction calls the conversion function and creates a temporary object. Probably it's better |
| 20 | +to disallow such reference binding. |
| 21 | +</p> |
| 22 | +</discussion> |
| 23 | + |
| 24 | +<resolution> |
| 25 | +<p> |
| 26 | +This wording is relative to <paper num="N5014"/> after application of <paper num="P3860R1"/>. |
| 27 | +</p> |
| 28 | + |
| 29 | +<blockquote class="note"> |
| 30 | +<p> |
| 31 | +[<i>Drafting note</i>: The deleted overloads were mirrored from the design of `reference_wrapper` before |
| 32 | +LWG <iref ref="2993"/>. As these overloads don't participate in implicit conversion, I don't think there |
| 33 | +will be any similar issue introduced.] |
| 34 | +</p> |
| 35 | +</blockquote> |
| 36 | + |
| 37 | +<ol> |
| 38 | +<li><p>Modify <sref ref="[atomics.ref.generic.general]"/>, primary class template `atomic_ref` synopsis, as indicated:</p> |
| 39 | + |
| 40 | +<blockquote> |
| 41 | +<pre> |
| 42 | +namespace std { |
| 43 | + template<class T> struct atomic_ref { |
| 44 | + private: |
| 45 | + T* ptr; <i>// exposition only</i> |
| 46 | + public: |
| 47 | + […] |
| 48 | + constexpr explicit atomic_ref(T&); |
| 49 | + <ins>explicit atomic_ref(T&&) = delete;</ins> |
| 50 | + constexpr atomic_ref(const atomic_ref&) noexcept; |
| 51 | + template<class U> |
| 52 | + constexpr atomic_ref(const atomic_ref<U>&) noexcept; |
| 53 | + […] |
| 54 | + }; |
| 55 | +} |
| 56 | +</pre> |
| 57 | +</blockquote> |
| 58 | +</li> |
| 59 | + |
| 60 | +<li><p>Modify <sref ref="[atomics.ref.int]"/>, class template `atomic_ref` <tt><i>integral-type</i></tt> |
| 61 | +specialization synopsis, as indicated:</p> |
| 62 | + |
| 63 | +<blockquote> |
| 64 | +<pre> |
| 65 | +namespace std { |
| 66 | + template<> struct atomic_ref<<i>integral-type</i>> { |
| 67 | + private: |
| 68 | + <i>integral-type</i>* ptr; <i>// exposition only</i> |
| 69 | + public: |
| 70 | + […] |
| 71 | + constexpr explicit atomic_ref(<i>integral-type</i>&); |
| 72 | + <ins>explicit atomic_ref(<i>integral-type</i>&&) = delete;</ins> |
| 73 | + constexpr atomic_ref(const atomic_ref&) noexcept; |
| 74 | + template<class U> |
| 75 | + constexpr atomic_ref(const atomic_ref<U>&) noexcept; |
| 76 | + […] |
| 77 | + }; |
| 78 | +} |
| 79 | +</pre> |
| 80 | +</blockquote> |
| 81 | +</li> |
| 82 | + |
| 83 | +<li><p>Modify <sref ref="[atomics.ref.float]"/>, class template `atomic_ref` <tt><i>floating-point-type</i></tt> |
| 84 | +specialization synopsis, as indicated:</p> |
| 85 | + |
| 86 | +<blockquote> |
| 87 | +<pre> |
| 88 | +namespace std { |
| 89 | + template<> struct atomic_ref<<i>floating-point-type</i>> { |
| 90 | + private: |
| 91 | + <i>floating-point-type</i>* ptr; <i>// exposition only</i> |
| 92 | + public: |
| 93 | + […] |
| 94 | + constexpr explicit atomic_ref(<i>floating-point-type</i>&); |
| 95 | + <ins>explicit atomic_ref(<i>floating-point-type</i>&&) = delete;</ins> |
| 96 | + constexpr atomic_ref(const atomic_ref&) noexcept; |
| 97 | + template<class U> |
| 98 | + constexpr atomic_ref(const atomic_ref<U>&) noexcept; |
| 99 | + […] |
| 100 | + }; |
| 101 | +} |
| 102 | +</pre> |
| 103 | +</blockquote> |
| 104 | +</li> |
| 105 | + |
| 106 | +<li><p>Modify <sref ref="[atomics.ref.pointer]"/>, class template `atomic_ref` <tt><i>pointer-type</i></tt> |
| 107 | +specialization synopsis, as indicated:</p> |
| 108 | + |
| 109 | +<blockquote> |
| 110 | +<pre> |
| 111 | +namespace std { |
| 112 | + template<> struct atomic_ref<<i>pointer-type</i>> { |
| 113 | + private: |
| 114 | + <i>pointer-type</i>* ptr; <i>// exposition only</i> |
| 115 | + public: |
| 116 | + […] |
| 117 | + constexpr explicit atomic_ref(<i>pointer-type</i>&); |
| 118 | + <ins>explicit atomic_ref(<i>pointer-type</i>&&) = delete;</ins> |
| 119 | + constexpr atomic_ref(const atomic_ref&) noexcept; |
| 120 | + template<class U> |
| 121 | + constexpr atomic_ref(const atomic_ref<U>&) noexcept; |
| 122 | + […] |
| 123 | + }; |
| 124 | +} |
| 125 | +</pre> |
| 126 | +</blockquote> |
| 127 | +</li> |
| 128 | +</ol> |
| 129 | +</resolution> |
| 130 | + |
| 131 | +</issue> |
0 commit comments