The following excerpt from the current draft shows what I mean:
namespace std {
typedef struct atomic_bool {
bool is_lock_free() const volatile;
bool is_lock_free() const;
void store(bool, memory_order = memory_order_seq_cst) volatile;
void store(bool, memory_order = memory_order_seq_cst);
bool load(memory_order = memory_order_seq_cst) const volatile;
bool load(memory_order = memory_order_seq_cst) const;
operator bool() const volatile;
operator bool() const;
bool exchange(bool, memory_order = memory_order_seq_cst) volatile;
bool exchange(bool, memory_order = memory_order_seq_cst);
bool compare_exchange_weak(bool&, bool, memory_order, memory_order) volatile;
bool compare_exchange_weak(bool&, bool, memory_order, memory_order);
bool compare_exchange_strong(bool&, bool, memory_order, memory_order) volatile;
bool compare_exchange_strong(bool&, bool, memory_order, memory_order);
bool compare_exchange_weak(bool&, bool, memory_order = memory_order_seq_cst) volatile;
bool compare_exchange_weak(bool&, bool, memory_order = memory_order_seq_cst);
bool compare_exchange_strong(bool&, bool, memory_order = memory_order_seq_cst) volatile;
bool compare_exchange_strong(bool&, bool, memory_order = memory_order_seq_cst);
atomic_bool() = default;
constexpr atomic_bool(bool);
atomic_bool(const atomic_bool&) = delete;
atomic_bool& operator=(const atomic_bool&) = delete;
atomic_bool& operator=(const atomic_bool&) volatile = delete;
bool operator=(bool) volatile;
} atomic_bool;
}
Volatile is transitive. Thus, you cannot call a non-volatile member function from a volatile object. On the other hand, calling a volatile member function from a non-volatile object is allowed.
So, is there any implementation difference between the volatile and non-volatile member functions in the atomic classes? In other words, is there any need for the non-volatile overload?
First, it sounds redundant to make a volatile std::atomic. Actually, I can imagine an useful situation. Assuming we have an fixed device (memory-)address we want to operate on. Due to the fact that the std::atomic_xxx classes as well as the std::atomic<> template class sizes should be same size as their corresponding built-in-types, you might want to handle both: Performing atomic operations with control over memory ordering and make sure that the access to our atomic-object is never optimized. Thus, we could declare something like: