This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

4472. std::atomic_ref<const T> can be constructed from temporaries

Section: 32.5.7 [atomics.ref.generic] Status: New Submitter: Jiang An Opened: 2025-11-11 Last modified: 2025-11-15

Priority: Not Prioritized

View all other issues in [atomics.ref.generic].

View all issues with New status.

Discussion:

std::atomic_ref<T> has a constructor taking T&, so when T is a const but not volatile object type, the constructor parameter can be bound to a temporary expression, which doesn't seem to make sense. Even after P3860R1, explicitly constructing std::atomic_ref<const T> from std::atomic_ref<volatile T> can be well-formed with the undesired semantics when it is well-formed to instantiate std::atomic_ref<volatile T> and its operator T conversion function, because the construction calls the conversion function and creates a temporary object. Probably it's better to disallow such reference binding.

Proposed resolution:

This wording is relative to N5014 after application of P3860R1.

[Drafting note: The deleted overloads were mirrored from the design of reference_wrapper before LWG 2993(i). As these overloads don't participate in implicit conversion, I don't think there will be any similar issue introduced.]

  1. Modify 32.5.7.1 [atomics.ref.generic.general], primary class template atomic_ref synopsis, as indicated:

    namespace std {
      template<class T> struct atomic_ref {
      private:
        T* ptr;               // exposition only
      public:
        […]
        constexpr explicit atomic_ref(T&);
        explicit atomic_ref(T&&) = delete;
        constexpr atomic_ref(const atomic_ref&) noexcept;
        template<class U>
          constexpr atomic_ref(const atomic_ref<U>&) noexcept;
        […]
      };
    }
    
  2. Modify 32.5.7.3 [atomics.ref.int], class template atomic_ref integral-type specialization synopsis, as indicated:

    namespace std {
      template<> struct atomic_ref<integral-type> {
      private:
        integral-type* ptr;               // exposition only
      public:
        […]
        constexpr explicit atomic_ref(integral-type&);
        explicit atomic_ref(integral-type&&) = delete;
        constexpr atomic_ref(const atomic_ref&) noexcept;
        template<class U>
          constexpr atomic_ref(const atomic_ref<U>&) noexcept;
        […]
      };
    }
    
  3. Modify 32.5.7.4 [atomics.ref.float], class template atomic_ref floating-point-type specialization synopsis, as indicated:

    namespace std {
      template<> struct atomic_ref<floating-point-type> {
      private:
        floating-point-type* ptr;               // exposition only
      public:
        […]
        constexpr explicit atomic_ref(floating-point-type&);
        explicit atomic_ref(floating-point-type&&) = delete;
        constexpr atomic_ref(const atomic_ref&) noexcept;
        template<class U>
          constexpr atomic_ref(const atomic_ref<U>&) noexcept;
        […]
      };
    }
    
  4. Modify 32.5.7.5 [atomics.ref.pointer], class template atomic_ref pointer-type specialization synopsis, as indicated:

    namespace std {
      template<> struct atomic_ref<pointer-type> {
      private:
        pointer-type* ptr;               // exposition only
      public:
        […]
        constexpr explicit atomic_ref(pointer-type&);
        explicit atomic_ref(pointer-type&&) = delete;
        constexpr atomic_ref(const atomic_ref&) noexcept;
        template<class U>
          constexpr atomic_ref(const atomic_ref<U>&) noexcept;
        […]
      };
    }