突破编程_C++_C++11新特性(type_traits的概念以及核心类型特性)

1 type_traits 的概述

type_traits 是 C++ 标准模板库(STL)中的一个头文件,它定义了一系列模板类,这些模板类在编译期获取某一参数、某一变量、某一个类等的类型信息,主要用于进行静态检查。通过使用 type_traits,程序员可以在编译时就获得关于类型的详细信息,从而可以在不实际运行程序的情况下进行类型相关的优化和检查。

type_traits 中的内容主要可以分为以下几类:

  • 辅助基类:如 std::integral_constant 以及其特化 true_type 和 false_type,这些类用于创建编译器常量,同时也是类型萃取类模板的基类。
  • 类型萃取类模板:这些模板类用于在编译期以常量的形式获取类型特征。例如,std::is_integral 用于检查一个类型是否为整数类型,std::is_floating_point 用于检查一个类型是否为浮点类型,std::is_base_of 用于检查一个类型是否是另一个类型的基类等。这些模板类主要用来进行类型属性的判断。
  • 类型转换类模板:这些模板类用于通过执行特定操作从已有类型获得新类型。例如,std::add_const 用于给类型添加 const 限定符,std::remove_volatile 用于移除类型的 volatile 限定符等。

type_traits 的主要作用包括:

  • 在编译期对类型进行属性检查和转换,避免了运行时的类型检查和转换开销。
  • 使得模板编程更加灵活和安全,可以在模板实例化之前根据类型属性选择不同的实现。
  • 为 STL 中的算法和容器提供了类型相关的支持,例如,STL 中的算法通过迭代器存取容器内容,而 type_traits 可以协助算法根据迭代器类型或容器类型选择不同的策略。

在 C++11 给出 type_traits 之前,对于类型处理有很多非常不方便的地方:

(1)类型信息的缺失: C++ 是一种静态类型语言,这意味着在编译时,每个变量和表达式都必须有明确的类型。然而,标准 C++ 并没有提供一个直接的机制来获取和操作这些类型信息。在没有 type_traits 的情况下,程序员通常需要手动跟踪和处理类型信息,这既繁琐又容易出错。

(2)模板元编程的复杂性: C++ 的模板元编程是一种在编译期进行计算和类型操作的技术。然而,由于缺乏 type_traits 这样的工具,模板元编程变得异常复杂和难以维护。程序员需要手动编写大量的模板特化和递归代码,以处理各种类型情况。这不仅增加了开发难度,也降低了代码的可读性和可维护性。

(13)类型安全和泛型编程的限制: 在泛型编程中,我们通常需要编写能够处理多种类型的代码。然而,在没有 type_traits 的情况下,我们很难在编译期对类型进行严格的检查和约束。这可能导致类型不安全的代码,例如,错误地将一个浮点数传递给期望整数的函数。此外,由于缺乏类型萃取和转换的工具,泛型编程的灵活性也会受到限制。

(4)性能优化的挑战: 在某些情况下,我们需要根据类型信息来优化代码的性能。例如,对于某些特定的类型,我们可能希望使用特定的算法或数据结构。然而,在没有 type_traits 的情况下,这种优化变得非常困难。我们需要编写复杂的条件编译代码,或者使用运行时类型信息(RTTI)来动态地选择实现。这些方法要么增加了编译的复杂性,要么引入了额外的运行时开销。

type_traits 的出现极大地缓解了这些挑战。它提供了一套丰富的工具,使得程序员可以在编译期获取和操作类型信息,从而简化了模板元编程,提高了类型安全性,并使得性能优化变得更加容易。通过使用 type_traits,可以编写更加灵活、安全和高效的 C++ 代码。

2 type_traits 核心类型特性

2.1 std::is_same

std::is_same 是一个模板类,用于检查两个类型是否相同。其定义如下:

template< class T, class U >  
struct is_same;

当 T 和 U 指名同一类型(考虑 const 和 volatile 限定)时,is_same<T, U>::value 为 true,否则为 false。

样例:

#include <iostream>  
#include <type_traits>  int main() {  std::cout << std::boolalpha; // 输出 true 或 false 而不是 1 或 0  std::cout << "int and int are " << std::is_same<int, int>::value << '\n'; // 输出 true  std::cout << "int and float are " << std::is_same<int, float>::value << '\n'; // 输出 false  return 0;  
}

2.2 std::is_integral

std::is_integral 是一个模板类,用于检查一个类型是否为整数类型。其定义如下:

template< class T >  
struct is_integral;

当 T 为整数类型时,is_integral<T>::value 为 true,否则为 false。

样例:

#include <iostream>  
#include <type_traits>  int main() {  std::cout << std::boolalpha;  std::cout << "int is " << std::is_integral<int>::value << '\n'; // 输出 true  std::cout << "double is " << std::is_integral<double>::value << '\n'; // 输出 false  return 0;  
}

2.3 std::is_floating_point

std::is_floating_point 是一个模板类,用于检查一个类型是否为浮点类型。其定义如下:

template< class T >  
struct is_floating_point;

当 T 为 float、double 或 long double(包括任何 cv 限定变体)时,is_floating_point<T>::value 为 true,否则为 false。

样例:

#include <iostream>  
#include <type_traits>  int main() {  std::cout << std::boolalpha;  std::cout << "float is " << std::is_floating_point<float>::value << '\n'; // 输出 true  std::cout << "int is " << std::is_floating_point<int>::value << '\n'; // 输出 false  return 0;  
}

2.4 std::is_array

std::is_array 是一个模板类,用于检查一个类型是否为数组类型。其定义如下:

template< class T >  
struct is_array;

当 T 为数组类型时,is_array<T>::value 为 true,否则为 false。

样例:

#include <iostream>  
#include <type_traits>  int main() {  std::cout << std::boolalpha;  std::cout << "int[5] is " << std::is_array<int[5]>::value << '\n'; // 输出 true  std::cout << "int is " << std::is_array<int>::value << '\n'; // 输出 false  return 0;  
}

2.5 std::is_pointer

std::is_pointer 是一个模板类,用于检查一个类型是否为指针类型。其定义如下:

template< class T >  
struct is_pointer;

当 T 为指针类型时,is_pointer<T>::value 为 true,否则为 false。

样例:

#include <iostream>  
#include <type_traits>  int main() {std::cout << std::boolalpha;std::cout << "int* is " << std::is_pointer<int*>::value << '\n'; // 输出 true  std::cout << "int is " << std::is_pointer<int>::value << '\n'; // 输出 false  return 0;
}

2.6 std::is_reference

std::is_reference 是一个模板类,用于检查一个类型是否为引用类型。其定义如下:

template< class T >  
struct is_reference;

当 T 为引用类型时,is_reference<T>::value 为 true,否则为 false。

样例:

#include <iostream>  
#include <type_traits>  int main() {  std::cout << std::boolalpha;  std::cout << "int& is " << std::is_reference<int&>::value << '\n'; // 输出 true  std::cout << "int is " << std::is_reference<int>::value << '\n'; // 输出 false  return 0;  
}

2.7 std::is_void

std::is_void 是一个模板类,用于检查一个类型是否为 void 类型。其定义如下:

template< class T >  
struct is_void;

当 T 为 void 类型时,is_void<T>::value 为 true,否则为 false。

样例:

#include <iostream>  
#include <type_traits>  int main() {  std::cout << std::boolalpha;  std::cout << "void is " << std::is_void<void>::value << '\n'; // 输出 true  std::cout << "int is " << std::is_void<int>::value << '\n'; // 输出 false  return 0;  
}

2.8 std::is_const

std::is_const 是一个模板类,用于检查一个类型是否为常量类型。其定义如下:

template< class T >  
struct is_const;

当 T 为常量类型时,is_const<T>::value 为 true,否则为 false。

样例:

#include <iostream>  
#include <type_traits>  int main() {  std::cout << std::boolalpha;  std::cout << "const int is " << std::is_const<const int>::value << '\n'; // 输出 true  std::cout << "int is " << std::is_const<int>::value << '\n'; // 输出 false  return 0;  
}

2.9 std::is_volatile

std::is_volatile 是一个模板类,用于检查一个类型是否为易变类型。其定义如下:

template< class T >  
struct is_volatile;

当 T 为易变类型时,is_volatile<T>::value 为 true,否则为 false。

样例:

#include <iostream>  
#include <type_traits>  int main() {  std::cout << std::boolalpha;  std::cout << "volatile int is " << std::is_volatile<volatile int>::value << '\n'; // 输出 true  std::cout << "int is " << std::is_volatile<int>::value << '\n'; // 输出 false  return 0;  
}

2.10 其他类型

除了上面介绍的类型,type_traits 还有如 std::is_signed (检查类型是否有符号)、std::is_unsigned (检查类型是否无符号)、std::is_arithmetic ( 检查类型是否为算术类型(整数或浮点数))等基础核心类型,具体的可以查看 C++ 标准中的类型说明。也可以通过查看头文件 <type_traits> 获得。

3 使用核心类型特性实现泛型编程中的条件编译

在 C++11 中,可以使用模板特化或者 std::enable_if 来实现类似条件编译的效果。下面是一个使用 std::is_same 和 std::is_integral 以及 std::enable_if 来实现泛型编程中条件编译的实例:

#include <iostream>  
#include <type_traits>  // 泛型函数模板,用于非整数类型  
template<typename T, typename = void>
void print_type_info(T value, typename std::enable_if<!std::is_integral<T>::value>::type* = nullptr) {std::cout << "Value is of a non-integral type." << std::endl;
}// 对 int 类型特化的版本  
template<typename T>
void print_type_info(T value, typename std::enable_if<std::is_same<T, int>::value>::type* = nullptr) {std::cout << "Value is of type int with value: " << value << std::endl;
}// 对整数类型特化的版本,但排除 int  
template<typename T>
void print_type_info(T value, typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, int>::value>::type* = nullptr) {std::cout << "Value is of an integral type (non-int) with value: " << value << std::endl;
}int main() {// 调用 print_type_info 模板函数,传入不同类型的值  print_type_info(12); // 调用 int 特化的版本  print_type_info(3.14f); // 调用非整数类型特化版本  print_type_info(static_cast<long long>(1234567890123456789)); // 调用整数类型特化的版本(排除 int)  return 0;
}

上面代码的输出为:

Value is of type int with value: 12
Value is of a non-integral type.
Value is of an integral type (non-int) with value: 1234567890123456789

这个例子定义了三个版本的 print_type_info 函数模板:

  • 一个非特化的版本,它接受非整数类型的参数 T,并打印一个通用消息。
  • 一个对 int 类型特化的版本,它只接受 int 类型的参数,并打印 int 类型的特定消息。
  • 一个对整数类型(除了 int)特化的版本,它接受任何整数类型(除了 int)的参数,并打印整数类型的特定消息。

std::enable_if 用于在编译时启用或禁用模板函数的不同特化版本。std::enable_if 的第二个模板参数是一个类型,当该类型存在时,模板会被启用;当该类型为 void 时,模板会被禁用。std::is_same<T, int>::value 和 std::is_integral<T>::value 用于在编译时检查类型。

4 使用核心类型特性实现类型安全的容器

下面是一个简单的类型安全整数容器的例子,它只允许存储整数类型,并且可以使用 std::is_same 来确保不添加与容器定义类型相同的类型:

#include <iostream>  
#include <type_traits>  
#include <vector>  
#include <stdexcept>  // 类型安全的整数容器  
template<typename T>
class TypeSafeIntegerContainer {
public:static_assert(std::is_integral<T>::value, "TypeSafeIntegerContainer can only hold integral types.");// 添加元素到容器中  template<typename U, typename = std::enable_if<std::is_integral<U>::value && !std::is_same<U, T>::value>>void add(U value) {// 检查新类型是否与 T 类型相同  static_assert(!std::is_same<U, T>::value, "Cannot add the same type to the container.");data.push_back(static_cast<T>(value));}// 获取容器中所有元素的数量  size_t size() const {return data.size();}// 打印容器中所有元素的值  void print() const {for (const auto& elem : data) {std::cout << elem << " ";}std::cout << std::endl;}private:std::vector<T> data; // 存储整数类型的容器  
};int main() 
{TypeSafeIntegerContainer<int> intContainer;// 添加不同类型的整数到容器中  intContainer.add(10L); // OK, long is converted to int  intContainer.add(20LL); // OK, long long is converted to int  intContainer.add(30U); // OK, unsigned int is converted to int  // 尝试添加相同类型的整数会导致编译错误  // intContainer.add(40); // 编译错误: Cannot add the same type to the container.  // 打印容器中的元素  intContainer.print(); // 输出: 10 20 30   // 尝试创建一个存储非整数类型的容器会导致编译错误  // TypeSafeIntegerContainer<std::string> stringContainer; // 编译错误: TypeSafeIntegerContainer can only hold integral types.  return 0;
}

上面代码的输出为:

10 20 30

在这个例子中,TypeSafeIntegerContainer 是一个模板类,它接受一个整数类型 T 作为模板参数。它有一个 add 成员函数模板,该函数模板只接受与 T 不同且为整数类型的参数。样例使用 std::enable_if_t 和 std::is_integral 来确保这一点。

这个例子还使用 static_assert 来确保在实例化 TypeSafeIntegerContainer 时,T 是一个整数类型,以及在调用 add 方法时,新类型 U 不与 T 相同。如果尝试添加与 T 类型相同的类型,或者尝试存储非整数类型,都会导致编译错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/764425.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

k8s-多容器Pod、容器保护策略、宽限期、最大生命周期、嵌入式脚本、多容器Pod、资源监控工具

资源对象文件 一、模板与帮助信息 1、资源对象文件优势 命令无法实现高级复杂的功能某些资源对象使用命令无法创建方便管理、保存、追溯历史 2、如何生成资源对象模板 资源对象 Pod 模板使用 run 生成 [rootmaster ~]# kubectl run myweb --imagemyos:nginx --dry-runcli…

10、chrome拓展程序的实现

一、拓展程序的实现 拓展程序项目的构成 和前端项目一样&#xff0c;拓展程序也是有Html、CSS、JS文件实现的&#xff0c;现在看来它就是一个静态的前端页面。但是不同的是&#xff0c;拓展程序中还需要额外的一个清单文件&#xff0c;就是manifest.json&#xff0c;清单文件可…

Prompt进阶系列5:LangGPT(提示链Prompt Chain)--提升模型鲁棒性

Prompt进阶系列5:LangGPT(提示链Prompt Chain)–提升模型鲁棒性 随着对大模型的应用实践的深入&#xff0c;许多大模型的使用者&#xff0c; Prompt 创作者对大模型的应用越来越得心应手。和 Prompt 有关的各种学习资料&#xff0c;各种优质内容也不断涌现。关于 Prompt 的实践…

SQLiteC/C++接口详细介绍sqlite3_stmt类(十)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;九&#xff09; 下一篇&#xff1a; SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;十一&#xff09; 38、sqlite3_column_value sqlite3_column_valu…

云计算系统等保测评对象和指标选取

1、云计算服务模式与控制范围关系 参考GBT22239-2019《基本要求》附录D 云计算应用场景说明。简要理解下图&#xff0c;主要是云计算系统安全保护责任分担原则和云服务模式适用性原则&#xff0c;指导后续的测评对象和指标选取。 2、测评对象选择 测评对象 IaaS模式 PaaS模式…

Python Flask 返回json类型数据

from flask import Flask, make_responseapp Flask(__name__)app.route("/") def hello():data {"name": "张三"}return make_response(data)if __name__ __main__:app.run(debugTrue)如果像返回字符串那么可以用 return make_response(json.…

HTML(二)

一、表格标签 1.1表格的主要作用 表格主要用于显示、展示数据&#xff0c;因为它可以让数据显示的非常的规整&#xff0c;可读性非常好。特别是后台展示数据的时候&#xff0c;能够熟练运用表格就显得很重要。一个清爽简约的表格能够把繁杂的数据表现得很有条理。 1.2 表格的…

工作量证明机制

引言 区块链是一几年极其火爆的技术概念,因为比特币的超高价格引起了公众对区块链技术的关注。犹记得当年各类区块链包装的应用游戏层出不穷,区块链所到之处,投资流量唾手可得,真可谓占尽天时,那种勃勃生机,万物竞发的境界,犹在眼前。短短十年之后,热度不在。不过也很…

鸿蒙一次开发,多端部署(十一)交互归一

对于不同类型的智能设备&#xff0c;用户可能有不同的交互方式&#xff0c;如通过触摸屏、鼠标、触控板等。如果针对不同的交互方式单独做适配&#xff0c;会增加开发工作量同时产生大量重复代码。为解决这一问题&#xff0c;我们统一了各种交互方式的API&#xff0c;即实现了交…

Spring Boot集成chronicle queue快速入门demo

1.chronicle queue介绍 Chronicle Queue使用一个内存映射文件来持久化每一条消息。这使我们能够在进程之间共享消息。它直接将数据存储到堆外内存&#xff0c;因此&#xff0c;使其没有GC开销。它被设计用来为高性能应用程序提供低延迟的消息框架。使用开源的Chronicle Queue可…

【SQL】1407. 排名靠前的旅行者

题目描述 leetcode题目&#xff1a;1407. 排名靠前的旅行者 Code 写法一 先过滤&#xff0c;再连表 -- 写法一&#xff1a;先过滤再连表 select name, ifnull(summ, 0) as travelled_distance from Users left join(select user_id, sum(distance) as summfrom Ridesgroup …

kubernetes K8s的监控系统Prometheus安装使用(一)

简单介绍 Prometheus 是一款基于时序数据库的开源监控告警系统&#xff0c;非常适合Kubernetes集群的监控。Prometheus的基本原理是通过HTTP协议周期性抓取被监控组件的状态&#xff0c;任意组件只要提供对应的HTTP接口就可以接入监控。不需要任何SDK或者其他的集成过程。这样做…

网络安全知识核心之RIP的工作原理

RIP 动态路由选择协议&#xff08;网络层协议&#xff09; RIP 是一种基于距离矢量&#xff08;Distance-Vector&#xff09;算法的协议&#xff0c;它使用跳数&#xff08;Hop Count&#xff09;作为度量来衡量到达目的网络的路由距离。RIP 通过 UDP 报文进行路由信息的交换&…

前端工程化的理解

简单来说&#xff0c;前端工程化是对前端开发流程的改良&#xff0c;是效率工具。 可以通过一下四个块来理解前端工程化 模块化&#xff1a; 就是将代码拆分&#xff0c;分成独立的单独的相互依赖的片段 首先说JS&#xff0c;CommonJS和ES Module都是JS模块化的一种表现形式&a…

TS + Vue3 elementUI 表格列表中如何方便的标识不同类型的内容,颜色区分 enum

TS Vue3 elementUI 表格列表中如何方便的标识不同类型的内容&#xff0c;颜色区分 enum 本文内容为 TypeScript 一、基础知识 在展示列表的时候&#xff0c;列表中的某个数据可能是一个类别&#xff0c;比如&#xff1a; enum EnumOrderStatus{"未受理" 1,"…

SQL执行原理

文章目录 SQL执行原理慢SQL分析优化案例优化步骤&#xff1a; 分库分表实施分库分表时&#xff0c;如何保证数据一致性&#xff1f;实践案例案例实施垂直拆分的步骤&#xff1a; SQL执行原理 SQL&#xff08;Structured Query Language&#xff09;是一种用于管理与查询关系数…

【LeetCode-74.搜索二维矩阵】

题目详情&#xff1a; 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true &#xff1b;否则&am…

Csharp学习Linq

Linq的学习 这里继续使用之前文章创建的学生类&#xff0c;首先简单介绍一下linq的使用。 Student.cs public class Student{public int Id { get; set; }public int ClassId { get; set; }public string Name { get; set; }public int Age { get; set; }public string Descr…

基于python+vue 的一加剧场管理系统的设计与实现flask-django-nodejs-php

二十一世纪我们的社会进入了信息时代&#xff0c;信息管理系统的建立&#xff0c;大大提高了人们信息化水平。传统的管理方式对时间、地点的限制太多&#xff0c;而在线管理系统刚好能满足这些需求&#xff0c;在线管理系统突破了传统管理方式的局限性。于是本文针对这一需求设…

Kubernetes自动化配置部署

在新建工程中&#xff0c;使用k8s的devops服务&#xff0c;自动化部署项目 1、在搭建好k8s的集群中&#xff0c;确认已开启devops服务&#xff1b; 2、新建Maven项目之后&#xff0c;创建dockerfile、deploy和Jenkins文件 例如&#xff1a; Dockerfile FROM bairong.k8s.m…