本篇文章就聊一下C++新特性 概念和约束
概念和约束的初步了解:
在C++中,概念(Concepts)是一种用于约束模板参数的机制。它们允许我们在使用模板时指定类型必须满足的条件,从而增强代码的可读性、可维护性和安全性。
通过定义概念,我们可以规定模板参数必须具备特定的属性、行为或操作符重载。例如,我们可以定义一个"可迭代"的概念,要求类型必须具有begin()和end()成员函数以支持范围遍历。然后,在使用这个概念作为模板参数时,只有满足该概念的类型才能被接受。
这种方式可以在编译期进行静态检查,提前发现错误,并避免不必要的运行时错误。它还可以提供更好的错误信息和友好的编译器提示。
一个代码有了概念 那么同时也就有了约束
概念和约束的C++ API:
std::enable_if
enable_if介绍:
enable_if
是C++中的一个类型特征工具,用于在编译期根据某些条件启用或禁用函数模板的实例化。
std::enable_if
是一个模板结构体,它有一个成员变量value
和一个成员类型type
。当给定条件为真时,value
将被设为true,同时定义了内部的type
类型别名;否则value
将被设为 false,并没有定义type
.通常情况下,我们将
std::enable_if<Condition, T>
作为函数模板参数的默认值,以便在满足某种条件时启用该模板的实例化。
代码实例:
template <typename T> typename std::enable_if<std::is_integral<T>::value, void>::type foo(T value) { // 只有当 T 是整型时,该函数才会被匹配并实例化 }
上述代码中,只有当
T
是整型(由std::is_integral<T>::value == true
判断)时,才会实例化这个函数模板。否则,编译器会忽略该函数模板的存在(在编译中会报错 )。这样可以在编译时根据条件选择合适的重载版本,并避免了在运行时进行判断和错误处理。通过合理地使用
std::enable_if
,可以实现更加灵活的模板编程。这里小编插一句 模板编程和模板元编程还是有区别的 模板编程还是依靠程序的运行中去解决问题 而模板元编程旨在程序的编译时期解决问题
到这里相信大家也看出 使用
enable_if技巧性太强 不好掌握 好在C++20出现了concept和requires关键字 可以将enable_if转换成concept或者requires
下面对这两个关键字进行介绍:
concept:
在编程中,"concept"是一个概念,用于描述一组满足特定要求的类型或模板参数。它是C++20引入的特性,用于进行类型约束和模板参数的静态检查。
通过使用"concept",可以定义一组条件,以确保传递给模板的类型或模板参数满足特定的要求。这样可以在编译时对代码进行更严格的类型检查,并提供更好的错误提示和自动补全功能。
使用"concept"可以增强代码的可读性、可维护性和安全性,并帮助开发者编写更健壮、高效的泛型代码。
template <class C> concept IntegerType = is_integral_v<C>; //此段代码的意思是约束函数模板的类型 如果不是整型 就会在编译阶段报错 //IntegerType 是一个概念名称 用来约束的
IntegerType 是概念名字 is_integral_v<C>是约束表达式 使用概念来使用约束表达式
概念---->约束
在C++20中,Concepts的引入增强了类型约束和模板的表达能力,它们目前可以支持逻辑操作符(如与、或、非)直接用于Concepts之间的组合。
例如:
concept SignedIntegerType = is_integral_v<C> && std::is_signed_v<C>; //合取
template <class C> concept IntegerFloatingType = is_integral_v<C> || is_floating_point<C>; //析取
require子句必须是一个类型为bool的常量表达式 合取或者析取
require:
require关键字就是将concept关键字进一步转化 能够很好的简化代码
template <class C> requires is_integral_v<C> //1.注意 这里没有分号 2.integral 是个概念 用来约束的
require表达式是一个纯右值表达式 表达式称为true表示满足约束条件 反之false表示不满足约束条件
requires表达式支持形参列表
a.clear()和a+b是要求序列
列如:
concept Check = requires(T a, T b) { a.clear(); a + b; };
原子约束:
原子约束是指表达式和表达式模板中模板形参到模板实参的映射组合(简称形参映射)
原子约束的判断方法
1.比较语义是否相同
2.比较映射关系是否相同
映射关系的比较:
requires Add1<2 * M> {};
requires Add<2*M>{};
两个函数映射是完全相同的 编译正确 通过
在这里 <2 * M>这一部分表示的是映射的关系 里面的参数列表要一模一样 包括顺序
反例:
template <int M> void f()
requires Add1<2 * M> {};
template <int M> void f()
requires Add1<M* 2> {};
f<0>();
在这段代码中 编译是失败的 因为他们的映射关系不一样 在这里的具体提现为顺序不同
代码实际使用案例:
#include <iostream> #include <concepts> template <typename T> concept Add1 = requires(T x) { { x + 1 } -> std::same_as<T>; }; template <int M> void f() requires Add1<2 * M> {} int main(int argc, char* argv[]) { f<0>(); return 0; }
总结:概念和约束的推行能够很好的补充C++的类型检查机制 对于库的创造者和使用者来说 都是一个好消息 可以让我们的错误能在编译的时候就能被检查出来 小编用的最多的还是requires 个人感觉比concept好用
好了 本篇文章就到这里 在这里小编想给大家推荐一个课程: