为什么我们需要 C++20 中的 concept 关键字?

问题描述 投票:0回答:1

概念很棒,不要误会我的意思,但是为什么我们需要另一个关键字呢?

考虑以下示例:

#include <type_traits>

template <typename T>
concept UnsignedConst = std::is_integral_v<T> && std::is_const_v<T>;

template <UnsignedConst T>
void foo(T bar);

我们也可以使用以下——在我看来更直接——语法:

/* ... */
template <typename T>
constexpr bool UnsignedConst = std::is_integral_v<T> && std::is_const_v<T>;
/* ... */

在幕后,概念只不过是取决于模板参数的编译时布尔常量。甚至

requires
子句也可以与变量模板一起使用,因为它们只是在编译时计算为布尔值的表达式。

c++ c++20 language-design c++-concepts
1个回答
2
投票

在幕后,概念只不过是取决于模板参数的编译时布尔常量。

这是不真实的。

A

concept
具有单纯的
constexpr bool
所没有的特殊属性。特别是,
concept
不能特化。这种无法专门化 使得概念包含规则 成为可能。它允许标准为模板的“更专业”版本制定规则。

鉴于以下情况:

template<typename T>
concept A = atomic_constraint_a<T>;

template<typename T>
concept B = atomic_constraint_a<T> && atomic_constraint_b<T>;

在 C++ 概念规则中很明显,

A
包含在
B
中。这意味着满足
T
 的任何类型 
B 必然 满足
A
。因此,如果您有两个模板,一个受
A
约束,一个受
B
约束,如果您传递满足
B
的类型,即使存在
A
的版本,也会选择该模板.

专门化会 ruin 这,因为有人可以来专门化

B
为类型
U
以这样的方式
A<U>
不包含
B<U>
.

那么……那会发生什么?当有人试图向具有竞争约束的上述模板提供

U
时会发生什么?主要约束说存在包含关系,但专门的约束没有。

更重要的是,我什至可以写两个具有包含关系的概念并确保这种关系得到维护吗?也就是说,在一个专业化的世界里,我可以在我的模板接口中依赖包容吗?

不,使包含成为可能的唯一方法是禁止专业化。但是变量模板可以专门化。所以现在你需要一个新的结构说“我有点像那个东西,但你不能专门化我”。我们可以让每个人都键入

template<typename T> [[nonspecialized]] inline constexpr bool concept_name = X
以获得包含(以及概念提供的其他东西)。

或者我们可以只说

template<typename T> concept concept_name = x
并消除一堆句法噪音。

此外,

concept
s 不能是类的成员。这也很重要,因为这意味着您不能通过专门化 around 概念的类来 de facto 专门化概念。

此外,通过使

concept
成为一种特殊的句法结构,由其自己的语法标记引入,它使语言能够更轻松地在新奇的地方使用
concept
。例如,
std::integral auto var_name = func();
。编译器可以看出
std::integral
是代表一个概念的标识符。如果它看到一个
constexpr bool
变量,您 可能 打算将它用作一个概念。或者您可能打算以其他方式使用它。通过使概念成为一种独特的事物,我们消除了任何歧义。

这就是允许我们在语法中以各种方式使用类型概念的原因,如果没有专门的语法,这将是……困难的事情。也许您可以将属性或其他内容应用于

constexpr inline bool
,但是再次...为什么所有关键字都只是指
concept

© www.soinside.com 2019 - 2024. All rights reserved.