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

### 768. Typos in [atomics]?

Section: 33.5.8 [atomics.types.generic] Status: CD1 Submitter: Alberto Ganesh Barbati Opened: 2007-12-28 Last modified: 2016-01-28

Priority: Not Prioritized

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

View all issues with CD1 status.

Discussion:

in the latest publicly available draft, paper N2641, in section 33.5.8 [atomics.types.generic], the following specialization of the template `atomic<>` is provided for pointers:

>     template <class T> struct atomic<T*> : atomic_address {
>       T* fetch_add(ptrdiff_t, memory_order = memory_order_seq_cst) volatile;
>       T* fetch_sub(ptrdiff_t, memory_order = memory_order_seq_cst) volatile;

>       atomic() = default;
>       constexpr explicit atomic(T);
>       atomic(const atomic&) = delete;
>       atomic& operator=(const atomic&) = delete;

>       T* operator=(T*) volatile;
>       T* operator++(int) volatile;
>       T* operator--(int) volatile;
>       T* operator++() volatile;
>       T* operator--() volatile;
>       T* operator+=(ptrdiff_t) volatile;
>       T* operator-=(ptrdiff_t) volatile;
>     };

First of all, there is a typo in the non-default constructor which should take a `T*` rather than a `T`.

As you can see, the specialization redefine and therefore hide a few methods from the base class `atomic_address`, namely `fetch_add`, `fetch_sub`, `operator=`, `operator+=` and `operator-=`. That's good, but... what happened to the other methods, in particular these ones:

>     void store(T*, memory_order = memory_order_seq_cst) volatile;
>     T* load( memory_order = memory_order_seq_cst ) volatile;
>     T* swap( T*, memory_order = memory_order_seq_cst ) volatile;
>     bool compare_swap( T*&, T*, memory_order, memory_order ) volatile;
>     bool compare_swap( T*&, T*, memory_order = memory_order_seq_cst ) volatile;

By reading paper N2427 "C++ Atomic Types and Operations", I see that the definition of the specialization `atomic<T*>` matches the one in the draft, but in the example implementation the methods `load()`, `swap()` and `compare_swap()` are indeed present.

Strangely, the example implementation does not redefine the method `store()`. It's true that a `T*` is always convertible to `void*`, but not hiding the `void*` signature from the base class makes the class error-prone to say the least: it lets you assign pointers of any type to a `T*`, without any hint from the compiler.

Is there a true intent to remove them from the specialization or are they just missing from the definition because of a mistake?

[ Bellevue: ]

> The proposed revisions are accepted.

> Further discussion: why is the ctor labeled "constexpr"? Lawrence said this permits the object to be statically initialized, and that's important because otherwise there would be a race condition on initialization.

Proposed resolution:

Change the synopsis in 33.5.8 [atomics.types.generic]:

>     template <class T> struct atomic<T*> : atomic_address {
>       void store(T*, memory_order = memory_order_seq_cst) volatile;
>       T* load( memory_order = memory_order_seq_cst ) volatile;
>       T* swap( T*, memory_order = memory_order_seq_cst ) volatile;
>       bool compare_swap( T*&, T*, memory_order, memory_order ) volatile;
>       bool compare_swap( T*&, T*, memory_order = memory_order_seq_cst ) volatile;

>       T* fetch_add(ptrdiff_t, memory_order = memory_order_seq_cst) volatile;
>       T* fetch_sub(ptrdiff_t, memory_order = memory_order_seq_cst) volatile;

>       atomic() = default;
>       constexpr explicit atomic(T*);
>       atomic(const atomic&) = delete;
>       atomic& operator=(const atomic&) = delete;

>       T* operator=(T*) volatile;
>       T* operator++(int) volatile;
>       T* operator--(int) volatile;
>       T* operator++() volatile;
>       T* operator--() volatile;
>       T* operator+=(ptrdiff_t) volatile;
>       T* operator-=(ptrdiff_t) volatile;
>     };