Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't C++20 use `requires` to restrict the T for atomic<T>?

A generic std::atomic<T> is required to have a T that is Copy Constructible and Copy Assignable:

[atomics.types.generic]/1

The program is ill-formed if any of

(1.1) is_­trivially_­copyable_­v<T>,
(1.2) is_­copy_­constructible_­v<T>,
(1.3) is_­move_­constructible_­v<T>,
(1.4) is_­copy_­assignable_­v<T>,
or (1.5) is_­move_­assignable_­v<T>

is false.

The above is not new to C++20. Compilers may use static_assert to issue an error for a non-conforming T.

However, C++20 could use formal constraints with the requires syntax to formally require the above as part of the type, e.g. something like:

template< class T > requires
    std::is_trivially_copyable_v<T> &&
    std::is_copy_constructible_v<T> &&
    std::is_move_constructible_v<T> &&
    std::is_copy_assignable_v<T> &&
    std::is_move_assignable_v<T>
struct atomic { ... };

Is there a reason why C++20 refrained from using formal constraints for this purpose?


EDIT: @T.C. points out correctly, in an answer below:

For std::atomic in particular, constraining the primary template is simply not an option, given the atomic<shared_ptr<T>> and atomic<weak_ptr<T>> specializations that were added in C++20.

with an option suggesting that:

Perhaps you can do something fancier (like an undefined and unconstrained primary template plus a constrained partial specialization), but it adds very little value.

Well, there is another option, without the need for an undefined and unconstrained primary template, which is still a bit complex and reduces the value and fun in going with concepts for this usage, but probably better than an undefined base template:

template< class T > requires
    std::is_trivially_copyable_v<T> &&
    std::is_copy_constructible_v<T> &&
    std::is_move_constructible_v<T> &&
    std::is_copy_assignable_v<T> &&
    std::is_move_assignable_v<T>
    || std::same_as<T, std::shared_ptr<typename T::element_type>>
    || std::same_as<T, std::weak_ptr<typename T::element_type>>
struct atomic { ... };

template< class T >
struct atomic<std::shared_ptr<T>> { ... };

template< class T >
struct atomic<std::weak_ptr<T>> { ... };

// types of all other specializations are Copy Constructible and Copy Assignable

Code: https://godbolt.org/z/JaCu78

like image 873
Amir Kirsh Avatar asked Sep 06 '25 03:09

Amir Kirsh


2 Answers

The library specification deliberately avoids using any particular technology to achieve its goals P0788:

IV. Let’s avoid any specification that demands any particular technology by which implementations must comply with Library specifications.

a) Let’s permit an implementation to use a requires-clause, an enable_if, a constexpr if, or any other technology or combination of technologies to meet Constraints: specifications.

b) Let’s permit an implementation to use static_assert and/or any other technologies to meet Mandates: specifications.

c) Let’s permit an implementation to use Contracts attributes [P0542R1] and/or any other technologies to meet Expects: and Ensures: specifications.

d) Let’s consider user code that relies on any specific technology on the part of an implementation to be ill-formed, with no diagnostic required.

Which is expanded upon in P1369.

The goal is to avoid tying the specification of the library to any particular implementation of it. There are cases where you do need to do this - many of the Ranges things do require concepts to work, so they are specified in this way - but for the most part, you don't.

For the user, the important part is the mandated requirements on T. It's not important how those requirements are enforced. It could be a concept, it could be a static_assert, it could be some compiler intrisic, whatever.

like image 163
Barry Avatar answered Sep 07 '25 23:09

Barry


For std::atomic in particular, constraining the primary template is simply not an option, given the atomic<shared_ptr<T>> and atomic<weak_ptr<T>> specializations that were added in C++20.

Perhaps you can do something fancier (like an undefined and unconstrained primary template plus a constrained partial specialization), but it adds very little value.

like image 29
T.C. Avatar answered Sep 07 '25 23:09

T.C.