当前位置: 首页 > news >正文

突破编程_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 之前&#xff0c;模板的解析和实例化过程中&#xff0c;右尖括号 > 的处理有时会导致一些意外的结果&#xff0c;特别是在嵌套模板或模板模板参数中。这是因为 C 编译器通常会试图“查看前方”来确定何时结束模板参数的列表&#xff0c;这有时…...

云原生消息流系统 Apache RocketMQ 在腾讯云的大规模生产实践

导语 随着云计算技术的日益成熟&#xff0c;云原生应用已逐渐成为企业数字化转型的核心驱动力。在这一大背景下&#xff0c;高效、稳定、可扩展的消息流系统显得尤为重要。腾讯云高级开发工程师李伟先生&#xff0c;凭借其深厚的技术功底和丰富的实战经验&#xff0c;为我们带…...

Node.js的事件驱动模型(非阻塞I/O)

Node.js的事件驱动模型是它能高效处理并发的关键。这个模型允许Node.js在单个线程上运行&#xff0c;同时通过非阻塞I/O操作来处理成千上万的并发连接。下面是对Node.js事件驱动模型的详细解释&#xff1a; 事件循环&#xff08;Event Loop&#xff09; 事件循环是Node.js事件…...

java过滤器Filter相关知识点汇总

1.Filter概述 Servlet Filter又称Servlet过滤器&#xff0c;它是在Servlet2.3规范中定义的&#xff0c;能够对Servlet容器传给Web资源的request对象和response对象执行检查和修改。 Filter不是Servlet&#xff0c;不能直接访问&#xff0c;其本身也不能生成request对象和resp…...

旅游景区公共广播 园区广播 公路服务区广播

旅游景区公共广播 园区广播 公路服务区广播 旅游景区公共广播 旅游景区公共广播(又称背景音乐)简称BGM&#xff0c;它的主要作用是掩盖噪声并创造一种轻松和谐的气氛&#xff0c;是一种创造轻松愉快环境气氛的音乐。掩盖环境噪声&#xff0c;创造与旅游景区相适应的气氛&#…...

Elastic Stack--09--ElasticsearchRestTemplate

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 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】聊天系统消息加密如何做

前言 先介绍一下对称加密算法&#xff0c;在介绍一下加密流程&#xff0c;然后是介绍一下查询加密消息的策略。然后结合现有技术架构然后去选型。 决定采用客户端解密。简而言之就是采用对称服务端加密。然后将加密内容存储到消息表的content字段。然后客户拉取content字段 然…...

网络建设与运维培训介绍和能力介绍

1.开过的发票 3.培训获奖的证书 4合同签署 5.实训设备...

3 种方法限制 K8s Pod 磁盘容量使用

容器在运行期间会产生临时文件、日志。如果没有任何配额机制&#xff0c;则某些容器可能很快将磁盘写满&#xff0c;影响宿主机内核和所有应用。 容器的临时存储&#xff0c;例如 emptyDir&#xff0c;位于目录/var/lib/kubelet/pods 下&#xff1a; /var/lib/kubelet/pods/ …...

05-ESP32-S3-IDF USART

ESP32-S3 IDF USART详解 USART简介 USART是一种串行通信协议&#xff0c;广泛应用于微控制器和计算机之间的通信。USART支持异步和同步模式&#xff0c;因此它可以在没有时钟信号的情况下&#xff08;异步模式&#xff09;或有时钟信号的情况下&#xff08;同步模式&#xff…...

安塔利斯升级php8

1、includes/classes/class.Database.php 255行 multi_query方法加返回类型 :bool query方法加返回类型&#xff1a;: mysqli_result|bool 2、includes/classes/class.Session.php on line 91 Optional parameter $planetID declared before required parameter $dpath is…...

Clickhouse MergeTree 原理(一)

作者&#xff1a;俊达 MergeTree是Clickhouse里最核心的存储引擎。Clickhouse里有一系列以MergeTree为基础的引擎&#xff08;见下图&#xff09;&#xff0c;理解了基础MergeTree&#xff0c;就能理解整个系列的MergeTree引擎的核心原理。 本文对MergeTree的基本原理进行介绍…...

【C语言】字符串函数上

&#x1f451;个人主页&#xff1a;啊Q闻 &#x1f387;收录专栏&#xff1a;《C语言》 &#x1f389;道阻且长&#xff0c;行则将至 前言 这篇博客是字符串函数上篇&#xff0c;主要是关于长度不受限制的字符串函数&#xff08;strlen,strcpy,strcat,strcm…...

Java集合基础知识总结(绝对经典)

List接口继承了Collection接口&#xff0c;定义一个允许重复项的有序集合。该接口不但能够对列表的一部分进行处理&#xff0c;还添加了面向位置的操作。 实际上有两种list&#xff1a;一种是基本的ArrayList&#xff0c;其优点在于随机访问元素&#xff0c;另一种是更强大的L…...

Linux:导出环境变量命令export

相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 Linux中的内建命令export命令用于创建一个环境变量&#xff0c;或将一个普通变量导出为环境变量&#xff0c;并且在这个过程中&#xff0c;可以给该环境变量赋值。 下面…...

案例--某站视频爬取

众所周知&#xff0c;某站的视频是&#xff1a; 由视频和音频分开的。 所以我们进行获取&#xff0c;需要分别获得它的音频和视频数据&#xff0c;然后进行音视频合并。 这么多年了&#xff0c;某站还是老样子&#xff0c;只要加个防盗链就能绕过。&#xff08;防止403&#xf…...

清华把大模型用于城市规划,回龙观和大红门地区成研究对象

引言&#xff1a;参与式城市规划的新篇章 随着城市化的不断推进&#xff0c;传统的城市规划方法面临着越来越多的挑战。这些方法往往需要大量的时间和人力&#xff0c;且严重依赖于经验丰富的城市规划师。为了应对这些挑战&#xff0c;参与式城市规划应运而生&#xff0c;它强…...

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的创意工坊双创管理…...

ARM指令追踪技术及TRCVICTLR寄存器详解

1. ARM指令追踪技术概述在嵌入式系统开发和调试过程中&#xff0c;指令追踪&#xff08;Instruction Trace&#xff09;是一项至关重要的技术。它通过硬件机制记录处理器的执行流程&#xff0c;为开发者提供程序运行的完整轨迹。ARM架构从v7开始引入嵌入式跟踪宏单元&#xff0…...

告别混乱绑定!在UE5 GAS中优雅管理技能输入(基于GameplayTag)

告别混乱绑定&#xff01;在UE5 GAS中优雅管理技能输入&#xff08;基于GameplayTag&#xff09;当你的UE5 RPG项目发展到中期&#xff0c;技能数量从十几个膨胀到几十个时&#xff0c;最痛苦的莫过于发现InputAction绑定已经变成一团乱麻。每次新增技能都要修改输入绑定逻辑&a…...

手把手教你用Mind+和Blynk,让手机轻松遥控掌控板(含自建服务器避坑指南)

从零搭建物联网控制平台&#xff1a;Mind与Blynk深度整合实战 当你第一次尝试用手机控制硬件设备时&#xff0c;那种"隔空取物"的奇妙感总会让人兴奋不已。想象一下&#xff0c;躺在沙发上就能调节书桌上的智能台灯亮度&#xff0c;或者在外出时随时查看家中的温湿度…...

Adobe-GenP 3.0:轻松激活Adobe全家桶的完整指南

Adobe-GenP 3.0&#xff1a;轻松激活Adobe全家桶的完整指南 【免费下载链接】Adobe-GenP Adobe CC 2019/2020/2021/2022/2023 GenP Universal Patch 3.0 项目地址: https://gitcode.com/gh_mirrors/ad/Adobe-GenP Adobe-GenP 3.0是一款专为Adobe Creative Cloud系列软件…...

利用FTDI芯片MPSSE模式构建Arduino兼容开发环境

1. 项目概述&#xff1a;当FTDI芯片遇上Arduino生态如果你手头有一些闲置的FTDI USB转串口模块&#xff0c;比如常见的FT232R、FT2232H&#xff0c;或者像我一样&#xff0c;从某个旧设备上拆下来一块FT2232C的老古董&#xff0c;除了用来给单片机烧录程序或者做串口调试&#…...

对比不同模型在创意生成任务中的效果与token消耗差异

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 对比不同模型在创意生成任务中的效果与token消耗差异 在为一场创意大赛准备素材时&#xff0c;我们面临一个常见的选择&#xff1a…...

Driver Store Explorer终极指南:轻松管理Windows驱动存储区,释放宝贵磁盘空间

Driver Store Explorer终极指南&#xff1a;轻松管理Windows驱动存储区&#xff0c;释放宝贵磁盘空间 【免费下载链接】DriverStoreExplorer Driver Store Explorer 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 你是否曾为Windows系统越来越慢而烦…...

开源三角洲机器人Delta-Robot One:从入门到精通的创客实践指南

1. 项目概述&#xff1a;一个为学习而生的开源三角洲机器人如果你对机器人感兴趣&#xff0c;但又觉得它高深莫测、无从下手&#xff0c;那么Delta-Robot One&#xff08;我们亲切地称它为“One”&#xff09;可能就是为你量身打造的入门项目。这不是一个遥不可及的工业设备&am…...

如何快速实现U盘文件自动备份:USBCopyer终极指南

如何快速实现U盘文件自动备份&#xff1a;USBCopyer终极指南 【免费下载链接】USBCopyer &#x1f609; 用于在插上U盘后自动按需复制该U盘的文件。”备份&偷U盘文件的神器”&#xff08;写作USBCopyer&#xff0c;读作USBCopier&#xff09; 项目地址: https://gitcode.…...

为什么你的霓虹总像“塑料灯带”?Midjourney光子散射模拟缺陷曝光:3个被官方隐瞒的--sref调参禁区

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;为什么你的霓虹总像“塑料灯带”&#xff1f; 霓虹效果在现代 UI 设计中无处不在——按钮悬停、加载指示器、焦点高亮……但多数实现却流于表面&#xff1a;生硬的 box-shadow、固定色值的渐变边框、缺乏物理感…...