c++ 新特性 概念和约束 “无规矩 难成方圆”

简介: c++ 新特性 概念和约束 “无规矩 难成方圆”

本篇文章就聊一下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出现了conceptrequires关键字 可以将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好用

好了 本篇文章就到这里 在这里小编想给大家推荐一个课程:

https://xxetb.xetslk.com/s/2PjJ3T

相关文章
|
1月前
|
编译器 程序员 定位技术
C++ 20新特性之Concepts
在C++ 20之前,我们在编写泛型代码时,模板参数的约束往往通过复杂的SFINAE(Substitution Failure Is Not An Error)策略或繁琐的Traits类来实现。这不仅难以阅读,也非常容易出错,导致很多程序员在提及泛型编程时,总是心有余悸、脊背发凉。 在没有引入Concepts之前,我们只能依靠经验和技巧来解读编译器给出的错误信息,很容易陷入“类型迷路”。这就好比在没有GPS导航的年代,我们依靠复杂的地图和模糊的方向指示去一个陌生的地点,很容易迷路。而Concepts的引入,就像是给C++的模板系统安装了一个GPS导航仪
104 59
|
1月前
|
存储 编译器 C++
【C++】面向对象编程的三大特性:深入解析多态机制(三)
【C++】面向对象编程的三大特性:深入解析多态机制
|
1月前
|
存储 编译器 C++
【C++】面向对象编程的三大特性:深入解析多态机制(二)
【C++】面向对象编程的三大特性:深入解析多态机制
|
1月前
|
编译器 C++
【C++】面向对象编程的三大特性:深入解析多态机制(一)
【C++】面向对象编程的三大特性:深入解析多态机制
|
1月前
|
存储 安全 编译器
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(一)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
29天前
|
C++
C++ 20新特性之结构化绑定
在C++ 20出现之前,当我们需要访问一个结构体或类的多个成员时,通常使用.或->操作符。对于复杂的数据结构,这种访问方式往往会显得冗长,也难以理解。C++ 20中引入的结构化绑定允许我们直接从一个聚合类型(比如:tuple、struct、class等)中提取出多个成员,并为它们分别命名。这一特性大大简化了对复杂数据结构的访问方式,使代码更加清晰、易读。
32 0
|
2月前
|
编译器 C++ 计算机视觉
C++ 11新特性之完美转发
C++ 11新特性之完美转发
50 4
|
2月前
|
Java C# C++
C++ 11新特性之语法甜点1
C++ 11新特性之语法甜点1
33 4
|
2月前
|
安全 程序员 编译器
C++ 11新特性之auto和decltype
C++ 11新特性之auto和decltype
39 3
|
2月前
|
编译器 C++ 容器
C++ 11新特性之语法甜点2
C++ 11新特性之语法甜点2
30 1