C++模板基础(七)

news/2025/2/25 8:08:28

Concept

-模板的问题:没有对模板参数引入相应的限制
-参数是否可以正常工作,通常需要阅读代码来理解

#include<iostream>
#include<vector>
template<typename T>
void fun()
{
	//...阅读代码来理解
}
int main()
{
	std::vector<int&> x; //“<template-parameter>”: 指向引用的指针非法
	return 0;
}

(C++20)Concept:编译期谓词,基于给定的输入,返回true或false
-与constraints(requires语句)一起使用限制模板参数,通常置于模板参数后面的尖括号后面进行限制

#include<iostream>
#include<vector>
#include<type_traits>
template<typename T>
concept IsAvail = std::is_same_v<T, int> || std::is_same_v<T, float>;

template<typename T>
requires IsAvail<T>
void fun(T input)
{
}
int main()
{
  fun(1); //OK
  fun(3.14); //OK
  fun(bool); //Error: candidate template ignored: constraints not satisfied
  return 0;
}

Concept的定义与使用
-包含一个模板参数的Concept
-使用requires语句
-直接替换typename

#include<iostream>
#include<vector>
#include<type_traits>
template<typename T>
concept IsAvail = std::is_same_v<T, int> || std::is_same_v<T, float>;

template<IsAvail T>
void fun(T input)
{
}
int main()
{
  fun(1); //OK
  fun(3.14); //OK
  return 0;
}

包含多个模板参数的Concept

#include<iostream>
#include<vector>
#include<type_traits>
template<typename T, typename T2>
concept IsAvail = std::is_same_v<T, T2>;

template<typename T>
void fun(T input)
{
}
int main()
{
  std::cout << IsAvail<int, float> << std::endl;
  return 0;
}
#include<iostream>
#include<vector>
#include<type_traits>
template<typename T, typename T2>
concept IsAvail = std::is_same_v<T, T2>;

template<typename T, typename T2>
requires IsAvail<T, T2>
void fun(T input, T2 input2)
{
  
}
int main()
{
  fun(3, 3.14); //Error: candidate template ignored: constraints not satisfied
  fun(3, 5); //OK
  return 0;
}
#include<iostream>
#include<vector>
#include<type_traits>
template<typename T, typename T2>
concept IsAvail = std::is_same_v<T, T2>;

template<typename T>
requires IsAvail<T, int>
void fun(T input)
{
  
}
int main()
{
  fun(3); //OK
  fun(3.14); //andidate template ignored: constraints not satisfied
  return 0;
}

-用作类型constraints时,少传递一个参数,推导出的类型将作为首个参数

requires表达式
-简单表达式:表明可以接收的操作

#include<iostream>
#include<vector>
#include<type_traits>
template<typename T>
concept Addable = requires(T a, T b) { a + b; };

template<Addable T>
auto fun(T x, T y)
{
	return x + y;
}
int main()
{
  fun(3, 5);
	return 0;
}

-类型表达式:表明是一个有效的类型

#include<iostream>
#include<vector>
#include<type_traits>
template<typename T>
concept Addable = requires(T a, T b) { a + b; };

template<Addable T>
auto fun(T x, T y)
{
	return x + y;
}

struct Str {};
int main()
{
  fun(3, 5); //OK
  
  Str a;
  Str b;
  fun(a, b); //Error: candidate template ignored: constraints not satisfied
  return 0;
}
#include<iostream>
#include<vector>
#include<type_traits>
template<typename T>
concept Avail = 
requires{
	typename T::inter;
};

template<Avail T>
auto fun(T x)
{
}

struct Str
{
	using inter = int;
};
int main()
{
  fun(2); //Error: unknown type name 'T' auto fun(T x)
  fun(Str{}); //OK
  return 0;
}

-复合表达式:表明操作的有效性,以及返回类型的特性

#include<iostream>
#include<vector>
#include<type_traits>
template<typename T>
concept Avail = 
requires (T x){
	{ x + 1 }->int;
};

template<Advail T>
auto fun(T x)
{
}

struct Str
{
	using inter = int;
};
int main()
{
	fun(3); //OK
	fun(Str{}); //Error: expected concept name with optional arguments { x + 1 }->int;
	return 0;
}

-嵌套表达式:包含其它的限定表达式
注意区分requires从句与requires表达式
requires从句会影响重载解析与特化版本的选取

#include<iostream>
#include<vector>
#include<type_traits>

template<typename T>
requires std::is_same_v<T, int>
void fun(T)
{

}

int main()
{
	fun(3); //OK
	return 0;
}
#include<iostream>
#include<vector>
#include<type_traits>

template<typename T>
requires std::is_same_v<T, float>
void fun(T)
{

}

int main()
{
	fun(3); //Error: candidate template ignored: constraints not satisfied
	return 0;
}

-只有requires从句有效而且返回为true时相应的模板才会被考虑

#include<iostream>
#include<vector>
#include<type_traits>
template<typename T>
requires std::is_same_v<T, int>
void fun(T)
{
	std::cout << "template<typename T> requires std::is_same_v<T, int> void fun(T)\n";
}

template<typename T>
requires std::is_same_v<T, float>
void fun(T)
{
	std::cout << "template<typename T> requires std::is_same_v<T, float> void fun(T)\n";
}

int main()
{
	fun(3); //输出template<typename T> requires std::is_same_v<T, int> void fun(T)
	return 0;
}

-requires从句所引入的限定具有偏序特性,系统会选择限制最严格的版本

#include<iostream>
#include<vector>
#include<type_traits>
template<typename T>
concept C1 = std::is_same_v<T, int>;

template<typename T>
concept C2 = std::is_same_v<T, int> || std::is_same_v<T, float>;

template<C1 T>
void fun(T)
{
	std::cout << "template<C1 T> void fun(T)\n";
}

template<C2 T>
void fun(T)
{
	std::cout << "template<C2 T> void fun(T)\n";
}

int main()
{
	fun(3); //输出template<C1 T> void fun(T)
	return 0;
}

偏特化小技巧:在声明中引入"A||B"进行限制,之后分别针对A与B引入特化

#include<iostream>
#include<vector>
#include<type_traits>
template<typename T>
class B;

template<>
class B<int> {};

template<>
class B<float> {};
int main()
{
	B<double> x; //Error: “x”使用未定义的 class“B<double>”
	return 0;
}
#include<iostream>
#include<vector>
#include<type_traits>
template<typename T>
	requires std::is_same<T, int> || std::is_same_v<T, float>
	//等同于requires std::is_integral_v<T> || std::is_floating_point_v<T>
class B;

template<>
class B<int> {};

template<>
class B<float> {};
int main()
{
	B<double> x; //Error: template constraints failure
	return 0;
}
#include<iostream>
#include<vector>
#include<type_traits>
template<typename T>
	requires std::is_integral_v<T> || std::is_floating_point_v<T>
class B;

template<typename T>
requires std::is_integral_v<T>
class B<T> {}; //class B {}; 不是特化

template<typename T>
requires std::is_floating_point_v<T>
class B<T> {}; //class B {}; 不是特化

struct Str {};
int main()
{
	B<double> x; //Error: aggregate 'B<double> x' has incomplete type and can not be defined
	B<Str> y; //Error: template constraints failure
	return 0;
}

参考
深蓝学院: C++基础与深度解析
约束与概念 (C++20 起)


http://www.niftyadmin.cn/n/200377.html

相关文章

Spring Bean的生命周期介绍

Spring Bean的生命周期源码链路思维导图流程图介绍SpringBean对象的生命周期视频介绍源码链路 refresh() finishBeanFactoryInitialization(beanFactory); beanFactory.preInstantiateSingletons(); getBean(beanName); doGetBean(name, null, null, false); createBean(beanNa…

class与namespace的区别

class也是一个名字空间&#xff0c;不过他是封闭的&#xff0c;也就是说你只能在一个文件里面定义class包含什么&#xff08;通俗点讲&#xff0c;就是一个class只能有一个头文件&#xff09;&#xff1b; namespace是开放的&#xff0c;和class不同的是你可以在多个文件里面象…

C程序设计语言基础

机器语言与高级语言 计算机硬件只能够识别电平信号&#xff0c;正电平或负电平&#xff0c;计算机的的各种按钮触发各种电平与计算机交互。随着随着操作系统的发展&#xff0c;人们用1&#xff0c;0分别表示正电平和负电平&#xff0c;并由0&#xff0c;1所组成的一系列指令指…

玩具产品发美国FBA头程走什么渠道比较划算

如果要将玩具产品发往美国FBA仓库&#xff0c;选择哪个渠道比较经济实惠呢?考虑到玩具产品在出口到美国中占据了较大的比例&#xff0c;有一点需要注意&#xff0c;在出口玩具产品前一定要做好CPC认证&#xff0c;只有通过CPC认证的产品才能发往美国FBA头程。那么&#xff0c;…

力扣每日一题【2399.检查相同字母间的距离】

力扣每日一题【2399.检查相同字母间的距离】 文章目录力扣每日一题【2399.检查相同字母间的距离】&#x1f34a;题目&#x1f34b;解析&#x1f966;代码&#x1f34a;题目 给你一个下标从 0 开始的字符串 s &#xff0c;该字符串仅由小写英文字母组成&#xff0c;s 中的每个字…

护眼灯哪些牌子好?2023热门护眼灯品牌推荐

护眼灯可以说是书桌的标配&#xff0c;不管是办公桌、书桌上&#xff0c;基本上有一盏辅助台灯&#xff0c;主要是就是补足室内环境亮度&#xff0c;市面上可以选择的护眼灯&#xff0c;可谓是琳琅满目&#xff0c;让人挑花眼&#xff0c;如果选择品质不好的台灯可能对眼睛造成…

Hilt进阶--本文带你吃透Hilt自定义与跨壁垒

跨越 IOC容器的壁垒 使用依赖注入&#xff08;DI&#xff09;时&#xff0c;我们需要它对 实例 、依赖关系 、 生命周期 进行管理&#xff0c;因此DI框架会构建一个容器&#xff0c;用于实现这些功能。这个容器我们惯称为IOC容器。 在容器中&#xff0c;会按照我们制定的规则…

ASP一个小型搜索引擎的设计与实现

本文通过分析国内外搜索引擎的发展现状&#xff0c;提出了一种功能强大&#xff0c;操作简单&#xff0c;通用性强&#xff0c;可以满足用户对信息搜索需要,利用ASP技术实现的一个B/S体系结构的搜索引擎系统方案。文中着重论述了该系统的功能与实现、数据流程与存储、后台管理等…