突破编程_C++_C++11新特性(模板的改进与细节)
1 模板右尖括号的改进
在 C++11 之前,模板的解析和实例化过程中,右尖括号 > 的处理有时会导致一些意外的结果,特别是在嵌套模板或模板模板参数中。这是因为 C++ 编译器通常会试图“查看前方”来确定何时结束模板参数的列表,这有时会导致解析错误。
C++11 对模板的右尖括号处理进行了改进,引入了两个新的规则:
- 列表初始化:当编译器在模板参数列表中遇到 > 时,它会首先尝试将其解释为列表初始化的结束符,而不是模板参数列表的结束符。这有助于解析像 std::vector<std::initializer_list<int>>这样的类型。
 - 模板参数推断:编译器在解析模板参数时,会进行更多的上下文检查来推断正确的解析方式。这有助于减少由于右尖括号导致的解析歧义。
 
下面是一些示例和解释:
示例 1:列表初始化
在 C++11 之前,如果需要这样声明一个 std::vector,其元素类型为 std::initializer_list<int>:
std::vector<std::initializer_list<int> > vec;
 
注意这里使用了额外的空格来避免编译器错误地将 > 解释为模板参数列表的结束符。
在 C++11 中,则可以这样写:
std::vector<std::initializer_list<int>> vec;
 
现在编译器会正确地解析它,而不需要额外的空格。
示例 2:模板模板参数
考虑以下嵌套模板的声明:
template<template<typename> class Outer, typename Inner>  
struct NestedTemplate {  Outer<Inner> obj;  
};  template<typename T>  
struct MyTemplate {  T value;  
};  int main() {  NestedTemplate<MyTemplate, int> nt;  return 0;  
}
 
在 C++11 之前,这样的代码可能会导致解析错误,因为编译器可能会错误地将 MyTemplate, int 解释为 NestedTemplate 的模板参数列表的结束。然而,在 C++11 中,由于引入了新的解析规则,这段代码可以正确编译。
如何启用这些改进
这些改进是 C++11 标准的一部分,因此你只需要确保你的编译器支持 C++11 或更高版本的标准。大多数现代编译器都默认支持 C++11,或者你可以通过编译器的命令行选项来明确指定使用 C++11(例如,在 GCC 和 Clang 中使用 -std=c++11)。
总体而言,C++11 对模板右尖括号的处理进行了改进,使得模板的声明和实例化更加直观和易于理解。通过引入列表初始化和模板参数推断的规则,C++11 减少了由于右尖括号导致的解析错误和歧义。使用 C++11 或更高版本可以利用这些改进来编写更清晰、更健壮的模板代码。
2 模板别名
C++11 的模板别名(Template Aliases)是一个新特性,它允许你为模板类型或模板函数创建一个别名,从而简化复杂模板类型的声明和使用。模板别名不仅提高了代码的可读性和可维护性,还使得模板的使用更加灵活。
2.1 模板类型别名
模板类型别名允许为复杂的模板类型定义一个简洁的名称。这特别适用于那些嵌套或带有大量模板参数的类型。
语法如下:
template<typename... Args>  
using AliasName = OriginalTemplateType<Args...>;
 
其中,AliasName 是定义的别名,OriginalTemplateType 是原始的模板类型,Args… 是模板参数。
示例:
假设有一个模板类 std::vector,它接受一个类型参数。则可以为这个模板类创建一个别名,以便更简洁地表示特定类型的 vector:
template<typename T>  
using Vec = std::vector<T>;  int main() 
{  Vec<int> intVec; // 等同于 std::vector<int> intVec;  Vec<double> doubleVec; // 等同于 std::vector<double> doubleVec;  return 0;  
}
 
在这个例子中,Vec 是 std::vector 的一个别名。使用 Vec 可以避免每次都需要写完整的 std::vector 类型,并且使得代码更加清晰。
2.2 模板函数别名
除了模板类型别名外,C++11 还允许为模板函数创建别名。这在处理重载函数或复杂函数签名时特别有用。
语法如下:
template<typename... Args>  
using AliasFunc = ReturnType OriginalFunctionName(Args...);
 
其中,AliasFunc 是函数别名,OriginalFunctionName 是原始函数名,ReturnType 是函数的返回类型,Args… 是函数的模板参数。
示例:
假设有一个模板函数,它接受两个相同类型的参数并返回它们的和:
template<typename T>  
T add(T a, T b) {  return a + b;  
}
 
则可以为这个模板函数创建一个别名:
template<typename T>  
using AddFunc = T(*)(T, T);  int main() 
{  AddFunc<int> addInts = add; // addInts 是指向 add 函数的指针  int sum = addInts(5, 3); // 调用 add 函数并计算 5 + 3  return 0;  
}
 
在这个例子中,AddFunc 是 add 函数的别名,它是一个函数指针类型。通过 AddFunc<int> addInts = add;,创建了一个指向 add<int> 函数的指针 addInts。然后,可以像调用普通函数一样调用 addInts。
2.3 总结
C++11 的模板别名特性为复杂的模板类型和函数提供了一个简洁的表示方式,提高了代码的可读性和可维护性。通过使用模板别名,可以避免在代码中重复编写冗长的模板类型和函数签名,使得代码更加清晰和易于理解。在实际开发中,可以根据需要灵活运用模板别名来简化复杂的模板用法。
3 默认模板参数
C++11 的默认模板参数允许在模板声明中为模板参数提供默认值。这大大增加了模板的灵活性和易用性。默认模板参数使得模板函数和模板类在调用或实例化时,如果未提供某些模板参数,则可以使用默认值。
3.1 模板函数默认参数
在 C++11 之前,模板函数是不支持默认参数的。然而,从 C++11 开始,这个限制被解除了。现在,可以为模板函数的模板参数提供默认值。
语法:
template<typename T = DefaultType>  
ReturnType functionName(Parameters);
 
其中,DefaultType 是模板参数 T 的默认值,ReturnType 是函数的返回类型,functionName 是函数名,Parameters 是函数的参数列表。
示例:
#include <iostream>  
#include <typeinfo>  template<typename T = int>
void printSize(T t = 0) {std::cout << "The sizeof " << typeid(T).name() << " is: " << sizeof(t) << std::endl;
}int main()
{printSize(); // 使用默认模板参数和函数参数,输出 int 的大小  printSize(1.0); // 使用浮点数推导模板参数,输出 double 的大小  printSize<char>('a'); // 指定模板参数为 char,输出 char 的大小  return 0;
}
 
上面代码的输出为:
The sizeof int is: 4
The sizeof double is: 8
The sizeof char is: 1
 
在上面的示例中,printSize 函数有一个默认模板参数 T,其默认值为 int。同时,该函数还有一个默认函数参数 t,其默认值为 0。这使得调用者可以选择性地提供模板参数和函数参数。
3.2 模板类默认参数
与模板函数类似,模板类也可以有默认模板参数。这对于创建更加通用且易于使用的模板类非常有用。
语法:
template<typename T1 = DefaultType1, typename T2 = DefaultType2, ...>  
class ClassName {  // 类成员和方法  
};
 
其中,DefaultType1、DefaultType2 等是模板参数 T1、T2 等的默认值,ClassName 是类名。
示例:
#include <iostream>  
#include <typeinfo>
#include <string>template<typename T1 = int, typename T2 = double>  
class Pair {  
public:  T1 first;  T2 second;  Pair(T1 f = T1(), T2 s = T2()) : first(f), second(s) {}  
};  int main() 
{  Pair<> p1; // 使用默认模板参数,T1 为 int,T2 为 double  Pair<std::string> p2; // 使用 std::string 作为 T1,T2 为默认的 double  Pair<char, long> p3('c', 123L); // 明确指定两个模板参数  return 0;  
}
 
在上面的示例中,Pair 类有两个默认模板参数 T1 和 T2,分别默认为 int 和 double。类的构造函数也有默认参数,使得对象的创建更加灵活。
3.3 模板类默认参数在模板类特化中的应用
在 C++ 中,模板类特化是一种为特定类型或类型组合提供模板类的特殊实现的技术。特化可以用于优化性能、添加特定类型的特定行为或提供类型无关的默认实现之外的特定实现。当与 C++11 的默认模板参数结合使用时,模板类特化可以变得更加灵活和强大。
默认模板参数允许在模板声明时为模板参数提供默认值。这样,在实例化模板类时,如果没有提供某些模板参数,编译器会使用默认值。当与模板类特化结合时,可以创建出既具有通用性又具有特定类型优化的代码结构。
以下是一些结合使用默认参数和特化应用场景:
(1)提供默认行为: 同时为特定类型优化:通过默认模板参数,可以为模板类提供一个通用的默认实现。然后,通过特化这个模板类,可以为特定类型提供优化的实现。
(2)处理复杂类型组合: 当模板类涉及多个类型参数时,可以使用部分特化来处理特定的类型组合。结合默认参数,可以进一步减少需要特化的情况,使代码更加简洁。
(3)扩展模板类的功能: 通过特化,可以为模板类添加新的成员函数或修改现有成员函数的行为。结合默认参数,可以确保在没有特化的情况下,模板类仍然具有可用的默认实现。
如下为样例代码:
#include <iostream>  
#include <string>  // 模板类定义,带有默认模板参数  
template<typename T1 = int, typename T2 = std::string>
class MyClass {
public:void print() {std::cout << "Default implementation for MyClass<" << typeid(T1).name() << ", " << typeid(T2).name() << ">" << std::endl;}
};// 模板类特化,针对特定类型组合的优化实现  
template<>
class MyClass<int, int> {
public:void print() {std::cout << "Specialized implementation for MyClass<int, int>" << std::endl;}
};int main() 
{// 使用默认模板参数实例化 MyClass  MyClass<> obj1;obj1.print(); // 输出默认实现  // 使用特定类型组合实例化 MyClass,触发特化  MyClass<int, int> obj2;obj2.print(); // 输出特化实现  // 使用其他类型组合实例化 MyClass  MyClass<double, std::string> obj3;obj3.print(); // 输出默认实现,因为没有针对这种类型组合的特化  return 0;
}
 
上面代码的输出为:
Default implementation for MyClass<int, class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >>
Specialized implementation for MyClass<int, int>
Default implementation for MyClass<double, class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >>
 
在上面的示例中,MyClass 是一个带有两个默认模板参数的模板类。当使用默认参数实例化时,会调用默认实现。然而,当使用 int 和 int 作为类型参数时,会触发特化版本的 MyClass,从而调用优化后的 print 方法。对于其他类型组合,仍然使用默认实现。
3.4 总结
C++11 的默认模板参数特性使得模板函数和模板类的使用更加简洁和灵活。通过为模板参数提供默认值,可以减少模板实例化时的冗余代码,并提高代码的可读性和可维护性。在实际开发中,合理利用默认模板参数可以极大地提高编程效率。
相关文章:
突破编程_C++_C++11新特性(模板的改进与细节)
1 模板右尖括号的改进 在 C11 之前,模板的解析和实例化过程中,右尖括号 > 的处理有时会导致一些意外的结果,特别是在嵌套模板或模板模板参数中。这是因为 C 编译器通常会试图“查看前方”来确定何时结束模板参数的列表,这有时…...
云原生消息流系统 Apache RocketMQ 在腾讯云的大规模生产实践
导语 随着云计算技术的日益成熟,云原生应用已逐渐成为企业数字化转型的核心驱动力。在这一大背景下,高效、稳定、可扩展的消息流系统显得尤为重要。腾讯云高级开发工程师李伟先生,凭借其深厚的技术功底和丰富的实战经验,为我们带…...
Node.js的事件驱动模型(非阻塞I/O)
Node.js的事件驱动模型是它能高效处理并发的关键。这个模型允许Node.js在单个线程上运行,同时通过非阻塞I/O操作来处理成千上万的并发连接。下面是对Node.js事件驱动模型的详细解释: 事件循环(Event Loop) 事件循环是Node.js事件…...
java过滤器Filter相关知识点汇总
1.Filter概述 Servlet Filter又称Servlet过滤器,它是在Servlet2.3规范中定义的,能够对Servlet容器传给Web资源的request对象和response对象执行检查和修改。 Filter不是Servlet,不能直接访问,其本身也不能生成request对象和resp…...
旅游景区公共广播 园区广播 公路服务区广播
旅游景区公共广播 园区广播 公路服务区广播 旅游景区公共广播 旅游景区公共广播(又称背景音乐)简称BGM,它的主要作用是掩盖噪声并创造一种轻松和谐的气氛,是一种创造轻松愉快环境气氛的音乐。掩盖环境噪声,创造与旅游景区相适应的气氛&#…...
Elastic Stack--09--ElasticsearchRestTemplate
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 spring-data-elasticsearch提供的APIQueryBuildersElasticsearchRestTemplate 方法ElasticsearchRestTemplate ---操作索引 ElasticsearchRestTemplate ---文档操作…...
论坛管理系统|基于Spring Boot+ Mysql+Java+B/S架构的论坛管理系统设计与实现(可运行源码+数据库+设计文档+部署说明+视频演示)
推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 目录 前台功能效果图 管理员功能登录前台功能效果图 用户功能模块 系统功能设计 数据库E-R图设计 l…...
2022 Task 2 Max Sum of 2 integers sharing first and last digits
Task 2 There is an array A consisting of N integers. What’s the maximum sum of two integers from A that share their first and last digits? For example, 1007 and 167 share their first(1) and last(7) digits, whereas 2002 and 55 do not. Write a function: …...
【分布式websocket】聊天系统消息加密如何做
前言 先介绍一下对称加密算法,在介绍一下加密流程,然后是介绍一下查询加密消息的策略。然后结合现有技术架构然后去选型。 决定采用客户端解密。简而言之就是采用对称服务端加密。然后将加密内容存储到消息表的content字段。然后客户拉取content字段 然…...
网络建设与运维培训介绍和能力介绍
1.开过的发票 3.培训获奖的证书 4合同签署 5.实训设备...
3 种方法限制 K8s Pod 磁盘容量使用
容器在运行期间会产生临时文件、日志。如果没有任何配额机制,则某些容器可能很快将磁盘写满,影响宿主机内核和所有应用。 容器的临时存储,例如 emptyDir,位于目录/var/lib/kubelet/pods 下: /var/lib/kubelet/pods/ …...
05-ESP32-S3-IDF USART
ESP32-S3 IDF USART详解 USART简介 USART是一种串行通信协议,广泛应用于微控制器和计算机之间的通信。USART支持异步和同步模式,因此它可以在没有时钟信号的情况下(异步模式)或有时钟信号的情况下(同步模式ÿ…...
安塔利斯升级php8
1、includes/classes/class.Database.php 255行 multi_query方法加返回类型 :bool query方法加返回类型:: mysqli_result|bool 2、includes/classes/class.Session.php on line 91 Optional parameter $planetID declared before required parameter $dpath is…...
Clickhouse MergeTree 原理(一)
作者:俊达 MergeTree是Clickhouse里最核心的存储引擎。Clickhouse里有一系列以MergeTree为基础的引擎(见下图),理解了基础MergeTree,就能理解整个系列的MergeTree引擎的核心原理。 本文对MergeTree的基本原理进行介绍…...
【C语言】字符串函数上
👑个人主页:啊Q闻 🎇收录专栏:《C语言》 🎉道阻且长,行则将至 前言 这篇博客是字符串函数上篇,主要是关于长度不受限制的字符串函数(strlen,strcpy,strcat,strcm…...
Java集合基础知识总结(绝对经典)
List接口继承了Collection接口,定义一个允许重复项的有序集合。该接口不但能够对列表的一部分进行处理,还添加了面向位置的操作。 实际上有两种list:一种是基本的ArrayList,其优点在于随机访问元素,另一种是更强大的L…...
Linux:导出环境变量命令export
相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 Linux中的内建命令export命令用于创建一个环境变量,或将一个普通变量导出为环境变量,并且在这个过程中,可以给该环境变量赋值。 下面…...
案例--某站视频爬取
众所周知,某站的视频是: 由视频和音频分开的。 所以我们进行获取,需要分别获得它的音频和视频数据,然后进行音视频合并。 这么多年了,某站还是老样子,只要加个防盗链就能绕过。(防止403…...
清华把大模型用于城市规划,回龙观和大红门地区成研究对象
引言:参与式城市规划的新篇章 随着城市化的不断推进,传统的城市规划方法面临着越来越多的挑战。这些方法往往需要大量的时间和人力,且严重依赖于经验丰富的城市规划师。为了应对这些挑战,参与式城市规划应运而生,它强…...
Vue+SpringBoot打造创意工坊双创管理系统
目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 管理员端2.2 Web 端2.3 移动端 三、系统展示四、核心代码4.1 查询项目4.2 移动端新增团队4.3 查询讲座4.4 讲座收藏4.5 小程序登录 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的创意工坊双创管理…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
