为什么 C++20 不使用 `requires` 来限制原子 <T> 的 T?

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

通用 std::atomic<T> 需要具有 T可复制构造可复制分配

[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>

false.

以上内容对 C++20 来说并不陌生。编译器可以使用 static_assert 为不符合要求的 T.

发出错误

但是,C++20 可以使用正式的 constraintsrequires 语法来正式要求上述内容作为一部分的类型,例如类似于:

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 { ... };

C++20 是否有理由避免为此目的使用正式的约束


编辑: @T.C. 正确指出,在下面的答案中:

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.

好吧,还有另一种选择,不需要 未定义和 不受约束的主模板,它仍然有点复杂,降低了使用概念的价值和乐趣,但可能比未定义的基本模板更好:

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

代码:https://godbolt.org/z/JaCu78

库规范有意避免使用任何特定技术来实现其目标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.

P1369 对其进行了扩展。

目标是避免将库的规范 绑定到它的任何特定实现。在某些情况下,您确实需要这样做——许多范围的事情确实需要概念才能起作用,所以它们是以这种方式指定的——但在大多数情况下,你不需要。

对于用户来说,重要的是 T 上的强制要求。 如何执行这些要求并不重要。它可能是一个概念,它可能是一个 static_assert,它可能是一些编译器的本质,无论如何。

特别是对于 std::atomic,考虑到在 C++20 中添加的 atomic<shared_ptr<T>>atomic<weak_ptr<T>> 特化,限制主模板根本不是一个选项。

也许您可以做一些更奇特的事情(比如未定义和不受约束的主模板加上受约束的偏特化),但它增加的价值很小。