C++20新特性_概念 (Concepts)

本文记录C++20新特性之概念(Concepts)。

文章目录

  • [第一章 C++20核心语法特性](#第一章 C++20核心语法特性)
    • [1.1 概念 (Concepts)](#1.1 概念 (Concepts))
      • [1.1.1 Concepts实现原理](#1.1.1 Concepts实现原理)
      • [1.1.2 concepts的使用举例](#1.1.2 concepts的使用举例)
        • [示例1 指定参数类型](#示例1 指定参数类型)
        • 示例2:约束成员函数
        • [示例3:基于 Concept 的函数重载](#示例3:基于 Concept 的函数重载)
      • [1.1.3 总结](#1.1.3 总结)

第一章 C++20核心语法特性

1.1 概念 (Concepts)

概念是C++20引入的新特性,用于模板编程中,被认为是C++11引入auto和lambda以来,模板编程中的最大变革。

C++20之前,模板编程(泛型编程)虽然强大,但存在两个著名的痛点:

缺点1: 不能精确定位错误位置:当向模板中传递一个不支持的类型时,编译器出现报错,但是不能精确指向哪一行,并支持错误。

缺点2:对预定类型的约束。在泛型编程时,想要指定某个函数模板T只能支持整型 或者 参数T必须有成员函数 hash(),通常使用SFINAE特性或enable_if来实现约束,这实现起来比较麻烦,请看《C++模板与泛型编程》笔记。

C++20引入了Concepts,就是为了给模板参数加上语义约束,如果参数传递错误,编译器给出清晰的错误提示,可轻松解决上面两个问题。

1.1.1 Concepts实现原理

concepts 本质上是编译期的谓词,用来约束类型,如果类型满足则返回true, 否则返回false.

语法:

concept: 定义概念

requires : 在模板中使用概念进行约束。

concepts的两个主要作用:

1 约束模板参数:明确指定模板参数必须满足的条件(如必须是整数、必须可排序)。

2 改善错误信息:如果约束不满足,编译器提示"类型不满足"这样的错误。

1.1.2 concepts的使用举例

示例1 指定参数类型

编写一个函数,必须接收int或浮点数类型的参数,不接收其他类型,实现如下:

cpp 复制代码
    // 1. 定义一个 Concept
    // T 必须是整数或浮点数
    template <typename T>
    concept Number = std::integral<T> || std::floating_point<T>;

    // 2. 使用 Concept 约束函数参数
	// 方式1:使用requires 关键字
    template<typename T>
		requires Number<T>
    void add(T a, T b)
    {
		std::cout << "Sum: " << (a + b) << std::endl;
    }

    // 写法B : 发直接替换typename 简洁
    void sub(Number auto a, Number auto b)
    {
		std::cout << "Difference: " << (a - b) << std::endl;
    }

    void test()
    {
        add(1, 2);
        sub(1, 2);

        // 传入字符串
       // add("aa", "bb");
        // "sp28::add": 未找到匹配的重载函数
    }
示例2:约束成员函数

在写模板编程时,要求类型T必须有一个hash()函数,且返回值为size_t.

cpp 复制代码
	// 假设要求类型T必须有一个hash()函数,且返回值为size_t
    template<typename T>
    concept Hashable = requires(T a) 
    {
        { a.hash() } -> std::same_as<size_t>;
        // 表达式 a.hash() 必须合法,且返回值必须能转换为 size_t
	};

    struct MyData 
    {
        size_t hash() const 
        {
            return 42; // 示例实现
        }
	};

    // 对象2 
    struct BadData 
    {
        int value;
        // 没有 hash() 方法
        void hash()
        {
            cout << "没有返回值的hash()" << endl;
        }
	};

	// 使用concept 约束函数
    void process(Hashable auto const& item)
    {
		std::cout << "Hash " << item.hash() << std::endl;
    }

    void test()
    {
        MyData d;
        process(d); // 合法
        // Hash 42

        BadData bd;
		//process(bd); // 编译错误,BadData 不满足 Hashable
        // 编译错误:"process": 未找到匹配的重载函数
    }
示例3:基于 Concept 的函数重载

指定某个重载版本的类型T必须支持随机访问。

cpp 复制代码
// 版本1: 支持任何标准容器
 template<typename T>
 void print(const T& t)
 {
     std::cout << "支持任意类型打印" << endl;
 }

 // 版本2:专门指针 可随机访问的容器
 template<typename T>
		requires std::ranges::random_access_range<T>
 void print(const T& t)
 {
		cout << "支持随机访问容器打印" << endl;
 }

 void test()
 {
		std::list<int> lst = { 1,2,3 };
		std::vector<int> vec = { 4,5,6 };

     print(lst); // 调用版本1
     // 支持任意类型打印
     print(vec); // 调用版本2
     /*
         支持随机访问容器打印
		*/
 }

1.1.3 总结

"concepts" 引入让模板代码更简介、更容易调试。以后写泛型编程时,尽量使用Concept进行约束。

std::ranges::random_access_range 也是C++20引入的新特性,见下。

相关推荐
啟明起鸣2 天前
【C++20新特性】概念约束特性与 “模板线程池”,概念约束是为了 “把握未知对象”
开发语言·c++·c++20·模板线程池
linweidong3 天前
虎牙C++面试题及参考答案(上)
stl·vector·线程·内存管理·c++20·c++面试·c++调用
吐泡泡_4 天前
C++20(概念和约束)
c++20
訫悦7 天前
体验在Qt中简单使用C++20的协程
qt·c++20·协程
fpcc11 天前
C++20中的预处理器宏——__VA_OPT__
c++20
Codeking__13 天前
C++20的consteval和constinit(接C++11的constexpr)
算法·c++20
六bring个六16 天前
C++20协程
c++20·协程
C++实习生16 天前
Visual C++ 2005 Express 中文版
express·c++20
Ethan Wilson18 天前
VS2019 C++20 模块相关 C1001: 内部编译器错误
开发语言·c++·c++20
DYS_房东的猫18 天前
《 C++ 零基础入门教程》第10章:C++20 核心特性 —— 编写更现代、更优雅的 C++
java·c++·c++20