为什么在C++20中需要concept关键字?

hrirmatl  于 2023-02-26  发布在  其他
关注(0)|答案(1)|浏览(180)

概念是伟大的,不要误解我,但为什么我们需要另一个关键字呢?
请看下面的例子:

#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>;
/* ... */

实际上,概念只不过是依赖于模板参数的编译时布尔常量(**EDIT:**NO!参见已接受的答案)。甚至requires-子句也可以与变量模板一起使用,因为它们只是在编译时求值为布尔值的表达式。

yws3nbqq

yws3nbqq1#

实际上,概念不过是依赖于模板参数的编译时布尔常量。
这是不真实的。
concept具有constexpr bool所不具备的特殊属性。特别是,concept不能被专门化。这种不能被专门化makes concept subsumption rules possible。它允许标准制定规则来定义模板的"更专门化"版本。
鉴于以下情况:

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中。这意味着任何满足B的类型T * 必然 * 满足A。因此,如果您有两个模板,一个约束在A上,另一个约束在B上,如果您传递满足B的类型,这是即使存在用于A的版本也将被选择的一个。
专门化会"毁了"这一点,因为有人可能会出现,并专门化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不能是类的成员,这也很重要,因为这意味着你不能通过围绕概念来专门化类,从而获得概念的事实上的专门化。
此外,通过使concept成为一个特殊的句法结构,由它自己的语法标记引入,它允许语言更容易地能够在新的地方使用concept。例如,std::integral auto var_name = func();。编译器可以看到std::integral是代表一个概念的标识符。如果它看到一个constexpr bool变量,你可能打算把它当作一个概念来使用,或者你可能打算以其他方式来使用它。2通过使概念成为一种独特的事物,我们消除了任何歧义。
这就是为什么我们可以在语法中以不同的方式使用类型概念,如果没有专门的语法,这将是...困难的。也许你可以有一个属性或其他东西应用到constexpr inline bool,但再次...为什么所有的关键字,当你只是指concept

相关问题