突破编程_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的创意工坊双创管理…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...

如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...