C++20 concepts

2024-07-18 13:18:10 浏览数 (2)

如果知道我会死在哪里,那我将永远不去那个地方 -查理 芒格

定义

概念(concepts),作为模板元编程(类模板和函数模板)的一部分,提出对模板实参的要求,进而影响模板的特化和函数重载。在编译期对实参求值,检测实参是否满足概念所提出的要求。

由以上定义中“在编译期对实参求值,检测实参是否满足概念所提出的要求”可知concepts实则为可以在编译期进行求值的模板类型的bool型变量。

进而的,concepts作为编译期进行求值的bool型变量,则可以对其进行&&、||、!操作,即concepts可以是单个/多个条件的交集、并集、补集。

定义

代码语言:javascript复制
template < 模板形参列表 >
concept 概念名 属性(可选) = 约束表达式;

使用示例

代码语言:javascript复制
#include <concepts>

template <typename T>
concept my_integeral = std::integral<T>;

template<my_integeral  T>
T add(T a, T b)
{
  return a b;
}

void using_concept()
{
  add(3,5);
  add(3.0, 5.0);//error
}

性质

概念不能递归地提及自身

代码语言:javascript复制
template<typename T>
concept V = V<T*>; //V<T>要求V<T*>也为真。这种递归定义在C  的概念中是不被允许的,会导致编译错误。

template<V C>
C sub(C a, C b)
{
  return a-b;
}

概念不能有关联的约束

代码语言:javascript复制
template<C1 T>
concept Error1 = true; //不能接受C1约束

template<class T> requires std::is_integral_v<T>
  concept Error2 = true; //不能接受requires约束

概念不能被显式实例化、显式特化或

部分特化

  1. 显式实例化:尝试为模板创建一个特定的类型实例。例如,对于一个模板类TemplateClass,我们可以尝试创建TemplateClass<int>的一个实例。
  2. 显式特化:为模板提供一个特定的类型版本。例如,我们可以为TemplateClass<int>提供一个特定的实现。
  3. 部分特化:为模板的某些类型参数提供特定的实现。例如,我们可以为TemplateClass<T, int>提供一个特定的实现。
代码语言:javascript复制
template <typename T>  
concept bool MyConcept = /* ... */;  
  
// 以下都是错误的  
MyConcept<int> obj;  // 错误:概念不能被显式实例化  
template <>  
concept bool MyConcept<int> = /* ... */;  // 错误:概念不能被显式特化  
template <typename U>  
concept bool MyConcept<U, int> = /* ... */;  // 错误:概念不能被部分特化

概念可以在标识表达式中使用

该标识表达式的值在满足约束表达式时是 true,否则是 false

代码语言:javascript复制
template <typename T>  
concept bool MyConcept = requires(T t) {  
    { t.foo() } -> std::same_as<void>;  
};  
  
int main() {  
    if constexpr (MyConcept<MyClass>) {  
        // MyClass满足MyConcept  
    } else {  
        // MyClass不满足MyConcept  
    }  
}

使用方法

常规使用方法

代码语言:javascript复制
template <typename T>
concept SignedIntegral = std::is_integral_v<T> && std::is_signed_v<T>;

template <SignedIntegral T>
void f1(T v)
{

}

template <typename T>
    requires SignedIntegral<T>
void f2(T v)
{
    
}

template <typename T>
void f3(T v) requires SignedIntegral<T>
{

}

void f4(SignedIntegral auto v)
{

}

template <SignedIntegral auto v>
void g2()
{

}

lambda表达式中使用

代码语言:javascript复制
auto f = []<SignedIntegral T> (T v) {
    // ...
};

auto f = []<typename T> requires SignedIntegral<T>(T v) {
    // ...
};

auto f = []<typename T> (T v) requires SignedIntegral<T> {
    // ...
};

auto f = [](SignedIntegral auto v) {
    // ...
    };

auto g = []<SignedIntegral auto v> () {
    // ...
};

参考文献:

https://zhuanlan.zhihu.com/p/266086040

Constraints and concepts (since C 20) - cppreference.com

0 人点赞