概念是伟大的,不要误解我,但为什么我们需要另一个关键字呢?
请看下面的例子:
#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
-子句也可以与变量模板一起使用,因为它们只是在编译时求值为布尔值的表达式。
1条答案
按热度按时间yws3nbqq1#
实际上,概念不过是依赖于模板参数的编译时布尔常量。
这是不真实的。
concept
具有constexpr bool
所不具备的特殊属性。特别是,concept
不能被专门化。这种不能被专门化makes concept subsumption rules possible。它允许标准制定规则来定义模板的"更专门化"版本。鉴于以下情况:
在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
?