突破编程_C++_C++11新特性(type_traits的属性类型特性以及操作类型特性)

1 type_traits 的属性类型特性

1.1 std::alignment_of

std::alignment_of 是一个模板类,用于获取类型的对齐要求。对齐是指数据在内存中的位置,某些硬件平台可能要求特定类型的数据位于特定地址的边界上。

定义:

template< class T >  
struct alignment_of;

样例:

#include <iostream>  
#include <type_traits>  int main() {std::cout << "Alignment of int: " << std::alignment_of<int>::value << std::endl;	std::cout << "Alignment of double: " << std::alignment_of<double>::value << std::endl;return 0;
}

上面代码输出为:

Alignment of int: 4
Alignment of double: 8

1.2 std::rank

std::rank 是一个模板类,用于获取数组类型的维度数。对于非数组类型,其值为 0。

定义:

template< class T >  
struct rank;

样例:

#include <iostream>  
#include <type_traits>  int main() {std::cout << "Rank of int: " << std::rank<int>::value << std::endl;std::cout << "Rank of int[3]: " << std::rank<int[3]>::value << std::endl;std::cout << "Rank of int[3][4]: " << std::rank<int[3][4]>::value << std::endl;return 0;
}

上面代码输出为:

Rank of int: 0
Rank of int[3]: 1
Rank of int[3][4]: 2

1.3 std::extent

std::extent 是一个模板类,用于获取数组类型的长度。它通常与 std::rank 结合使用,以确定特定维度的长度。

定义:

template< class _Ty, unsigned int _Nx = 0 >  
struct extent;

样例:

#include <iostream>  
#include <type_traits>  int main() {std::cout << "Rank of int: " << std::rank<int>::value << std::endl;std::cout << "Rank of int[3]: " << std::rank<int[3]>::value << std::endl;std::cout << "Rank of int[3][4]: " << std::rank<int[3][4]>::value << std::endl;return 0;
}

上面代码输出为:

Extent of int[3]: 3
First dimension extent of int[3][4]: 3
Second dimension extent of int[3][4]: 4

1.4 std::remove_all_extents

std::remove_all_extents 是一个模板类,用于移除数组类型的所有维度,将其转换为其元素类型。换句话说,它将多维数组转换为其基础元素类型。

定义:

template< class T >  
struct remove_all_extents;

样例:

#include <iostream>  
#include <type_traits>  int main() {  std::cout << typeid(std::remove_all_extents<int[3][4]>::type).name() << std::endl;  return 0;  
}

上面代码输出为:

int

注意:typeid(T).name() 在不同的编译器和平台上可能会返回不同的字符串,因此上述输出可能会因环境而异。但核心思想是 std::remove_all_extents 将数组类型转换为其基础元素类型。

2 std::rank 与 std::extent 的综合应用示例

std::rank 和 std::extent 分别用于获取数组或指针类型的维度数和特定维度的长度。这两个工具在泛型编程和模板元编程中特别有用,尤其是在处理不同维度的数组或指针类型时。

下面是一个综合使用 std::rank 和 std::extent 的真实应用场景示例:一个函数模板,用于打印任意维度数组的形状(即各维度的长度)。

#include <iostream>  
#include <type_traits>  // 递归辅助函数模板,用于打印数组形状  
template <typename T, std::size_t N = std::rank<T>::value>
struct print_array_shape_helper;// 特化:数组维度为0时,结束递归  
template <typename T>
struct print_array_shape_helper<T, 0> {static void print(const T&) {// 无需打印,因为没有更多维度  }
};// 递归情况:打印当前维度大小,并递归调用下一个维度  
template <typename T, std::size_t N>
struct print_array_shape_helper {static void print(const T& arr) {std::cout << std::extent<T, N - 1>::value << " ";print_array_shape_helper<T, N - 1>::print(arr);}
};// 打印数组形状的包装函数  
template <typename T>
void print_array_shape(const T& arr) {constexpr std::size_t rank = std::rank<T>::value;if (rank > 0) {std::cout << "Array shape: ";print_array_shape_helper<T, rank>::print(arr);std::cout << std::endl;}else {std::cout << "Not an array type." << std::endl;}
}int main() 
{// 一维数组  int arr1[] = { 1, 2, 3, 4, 5 };print_array_shape(arr1); // 输出: Array shape: 5  // 二维数组  int arr2[][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };print_array_shape(arr2); // 输出: Array shape: 3 3  // 不是数组的类型  int non_array = 42;print_array_shape(non_array); // 输出: Not an array type.  return 0;
}

上面代码的输出为:

Array shape: 5
Array shape: 3 3
Not an array type.

在这个示例中,print_array_shape 函数模板接受一个数组作为参数,并使用 std::rank 来确定其维度数(即秩)。然后,它使用 std::make_index_sequence 生成一个从 0 到 rank - 1 的索引序列,并将其传递给 print_array_shape_impl 函数模板。

print_array_shape_impl 函数模板接受一个数组和一个索引序列作为参数。它使用折叠表达式(C++17及更高版本中的特性)和 std::extent 来遍历数组的每一个维度,并打印出每一维的长度。

通过这种方式,我们可以编写一个通用的函数来打印任意维度数组的形状,而无需事先知道数组的确切维度数。这种技术对于处理不同大小和维度的数组非常有用,尤其是在科学计算、数据分析或任何需要处理多维数据的领域中。

3 type_traits 的操作类型特性

3.1 std::conditional

std::conditional 是一个模板类,它接受一个布尔条件、两个类型 T 和 F 作为模板参数,然后根据条件在 T 和 F 之间选择一个类型。如果条件为 true,则选择 T,否则选择 F。

定义:

template<class _Ty1,class _Ty2>
struct conditional<true, _Ty1, _Ty2>

样例:

#include <iostream>  
#include <type_traits>  int main() {using Type1 = std::conditional<true, int, double>::type; // Type1 是 int  using Type2 = std::conditional<false, int, double>::type; // Type2 是 double  std::cout << typeid(Type1).name() << std::endl; std::cout << typeid(Type2).name() << std::endl; return 0;
}

上面代码输出为:

int
double

3.2 std::common_type

std::common_type 是一个模板类,它接受多个类型作为模板参数,并确定这些类型的公共类型。如果所有类型都可以隐式转换为某个类型,那么 common_type 就是该类型。

定义:

template<class _Ty1,class _Ty2,class... _Rest>
struct common_type<_Ty1, _Ty2, _Rest...> : _Common_type3<void, _Ty1, _Ty2, _Rest...>

样例:

#include <iostream>  
#include <type_traits>  int main() {  using CommonType = std::common_type<int, float, double>::type; // CommonType 是 double  std::cout << typeid(CommonType).name() << std::endl; return 0;  
}

上面代码输出为:

double

3.3 std::decay

std::decay 是一个模板类,它接受一个类型作为模板参数,并产生一个“衰减”后的类型。这通常意味着它会去除引用和 CV 限定符(const 和 volatile),如果是数组或函数类型,则会转换为对应的指针类型。

定义:

template<class T>
struct decay

样例:

#include <iostream>  
#include <type_traits>  int main() {using DecayedType = std::decay<int&>::type; // DecayedType 是 int  using DecayedArrayType = std::decay<int[5]>::type; // DecayedArrayType 是 int*  std::cout << typeid(DecayedType).name() << std::endl; std::cout << typeid(DecayedArrayType).name() << std::endl; return 0;
}

上面代码输出为:

int
int * __ptr64

3.4 std::enable_if

std::enable_if 是一个模板类,它根据一个布尔条件来启用或禁用模板特化。它通常与 std::is_same、std::is_integral 等类型特性检查模板结合使用,以在编译时根据类型特性进行条件编译。

定义:

template<bool _Test,class _Ty = void>
struct enable_if

样例:

#include <iostream>  
#include <type_traits>  template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
void foo(T) {std::cout << "Integral type." << std::endl;
}template<typename T, typename std::enable_if<!std::is_integral<T>::value, int>::type = 0>
void foo(T) {std::cout << "Non-integral type." << std::endl;
}int main() {foo(12);  foo(3.14); return 0;
}

上面代码输出为:

Integral type.
Non-integral type.

4 std::conditional 应用于类型包装器

下面是一个使用 std::conditional 的示例,展示了如何在模板中基于类型属性选择一个类类型或者类型别名:

#include <iostream>  
#include <type_traits>  // 整数类型包装器  
template<typename T>
struct IntegerWrapper {T value;IntegerWrapper(T v) : value(v) {}void print() const {std::cout << "Integer: " << value << std::endl;}
};// 浮点类型包装器  
template<typename T>
struct FloatWrapper {T value;FloatWrapper(T v) : value(v) {}void print() const {std::cout << "Float: " << value << std::endl;}
};// 使用std::conditional根据类型属性选择包装器  
template<typename T>
using WrapperType = typename std::conditional<std::is_integral<T>::value,IntegerWrapper<T>,FloatWrapper<T>
>::type;int main() {// 使用WrapperType为整数类型选择包装器  WrapperType<int> intWrapper(12);intWrapper.print(); // 输出 "Integer: 12"  // 使用WrapperType为浮点类型选择包装器  WrapperType<double> floatWrapper(3.14);floatWrapper.print(); // 输出 "Float: 3.14"  return 0;
}

上面代码输出为:

Integer: 12
Float: 3.14

这个示例定义了两个模板包装器:IntegerWrapper 用于整数类型,FloatWrapper 用于浮点类型。然后,使用 std::conditional 来根据类型 T 是否为整数类型来选择相应的包装器。这里 std::conditional 有三个模板参数:第一个是一个布尔表达式,第二个是在表达式为 true 时选择的类型,第三个是在表达式为 false 时选择的类型。

WrapperType 是一个类型别名模板,它使用了 std::conditional 来选择适当的包装器类型。然后,在 main 函数中,分别创建了一个整数类型的包装器和一个浮点类型的包装器,并调用了它们的 print 方法。

5 std::enable_if 应用于类型安全的加法函数

下面示例是一个简单的类型安全的加法函数,它根据输入类型选择不同的加法实现:

#include <iostream>  
#include <type_traits>  // 整数加法  
template<typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
add(T a, T b) {return a + b;
}// 浮点加法  
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
add(T a, T b) {return a + b;
}// 通用加法包装器 
template<typename T>
auto add_wrapper(T a, T b) -> decltype(add(a, b)) {return add(a, b);
}template<typename T, bool IsIntegral>
struct adder;template<typename T>
struct adder<T, true> {static T add(T a, T b) {return a + b; // 整数加法实现  }
};template<typename T>
struct adder<T, false> {static T add(T a, T b) {return a + b; // 浮点加法实现(假设T是浮点类型)  }
};// 使用std::conditional来选择加法器实现  
template<typename T>
T conditional_add(T a, T b) {return adder<T, std::is_integral<T>::value>::add(a, b);
}int main() 
{// 使用add_wrapper进行整数加法  std::cout << "5 + 3 (integers) = " << add_wrapper(5, 3) << std::endl;// 使用add_wrapper进行浮点加法  std::cout << "5.0 + 3.0 (floats) = " << add_wrapper(5.0, 3.0) << std::endl;// 使用conditional_add进行整数加法  std::cout << "5 + 3 (integers via conditional) = " << conditional_add(5, 3) << std::endl;// 使用conditional_add进行浮点加法  std::cout << "5.0 + 3.0 (floats via conditional) = " << conditional_add(5.0, 3.0) << std::endl;return 0;
}

上面代码输出为:

5 + 3 (integers) = 8
5.0 + 3.0 (floats) = 8
5 + 3 (integers via conditional) = 8
5.0 + 3.0 (floats via conditional) = 8

这个示例定义了两个重载的 add 函数模板,分别用于整数和浮点数的加法。然后创建了一个 add_wrapper 函数模板,它使用 decltype 和 enable_if 来根据参数类型选择正确的 add 函数。

这种基于条件的类型选择在模板元编程中非常常见,允许程序员编写更加通用和灵活的代码,同时保持类型安全。

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

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

相关文章

Github 2024-03-23 Rust开源项目日报 Top10

根据Github Trendings的统计,今日(2024-03-23统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Dart项目1RustDesk: 用Rust编写的开源远程桌面软件 创建周期:1218 天开发语言:Rust, Dart协议类型:GNU Affero General Public Li…

在离线的arm架构kylin v10服务器上使用Kuboard-Spray搭建K8S集群

在离线的arm架构kylin v10服务器上使用Kuboard-Spray搭建K8S集群 在内网项目中需要安装K8S集群&#xff0c;经过调研&#xff0c;选择使用Kuboard-Spray工具搭建K8S集群&#xff0c;降低学习成本&#xff0c;提高安装效率。 为了简化安装使用集群的过程&#xff0c;搭建了私有…

云计算 3月18号 (mysql安装及操作)

一、Mysql 1.1 MySQL数据库介绍 1.1.1 什么是数据库DB&#xff1f; DB的全称是database&#xff0c;即数据库的意思。数据库实际上就是一个文件集合&#xff0c;是一个存储数据的仓库&#xff0c;数据库是按照特定的格式把数据存储起来&#xff0c;用户可以对存储的数据进行…

Docker 容器中使用 RAM 角色实现云监控事件监控

准备工作 在开始之前,请确保您已经完成以下准备工作: 创建一个 RAM 角色,并为该角色授予 ​​AliyunCloudMonitorFullAccess​​ 权限。这将允许该角色执行云监控服务的所有操作,包括发送自定义事件。准备一个 Python 应用程序,用于发送自定义事件到云监控服务。您可以使用我们…

jupyter notebook和jupyter lab 找不到虚拟环境

文章目录 这里以环境Pytorch为例&#xff1a; 激活环境 conda activate Pytorch在你的环境中安装 ipykernel&#xff1a; conda install ipykernel将你的环境添加到 Jupyter 的内核列表中&#xff1a; python -m ipykernel install --user --namePytorch

spring boot高级运用:使用Spring Kafka集成Apache Kafka,实现消息的生产和消费。

使用Spring Kafka集成Apache Kafka&#xff0c;实现消息的生产和消费。 要使用Spring Kafka集成Apache Kafka来实现消息的生产和消费&#xff0c;您需要进行以下步骤&#xff1a; 添加Spring Kafka依赖&#xff1a; 在您的Spring Boot项目中&#xff0c;首先需要添加Spring …

Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用

探索Java高级编程&#xff1a;综合性面试题解析 Java作为一门功能强大的编程语言&#xff0c;在企业级应用开发中占据着举足轻重的地位。本文将深入探讨Java设计模式、内存管理、多线程工具类、并发工具包和并发框架等高级知识点&#xff0c;通过三道综合性的面试题&#xff0…

Python 从0开始 一步步基于Django创建项目(4)应用Django shell查看数据模型

Django shell是Django提供的交互式环境&#xff0c;可以通过编程的方式查看数据模型中的数据。 在《Python 从0开始 一步步基于Django创建项目&#xff08;3&#xff09;》中已经向数据模型city&#xff0c;添加了两条数据&#xff1a;‘北京’、‘墨尔本’。又向数据模型entr…

2、事件修饰符、双向绑定、style样式使用、v-for循环遍历、v-if 和 v-show

一、事件修饰符 1、.stop 阻止冒泡事件 给谁加了阻止冒泡事件&#xff0c;谁下面的盒子就不会执行了 <div id"app"><div class"parent" click"log3"><div class"child" click"log2"><button click.…

AI:151-使用机器学习技术进行信用风险评估与管理

收录于专栏:精通AI实战千例专栏合集 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带关键代码,详细讲解供大家学习,希望可以帮到大家。正在不断更新中~ 一.机器学习在信用风险评估与管理中…

python蓝桥杯-算法训练 印章、拿金币、数字游戏

一、印章 问题描述 共有n种图案的印章&#xff0c;每种图案的出现概率相同。小A买了m张印章&#xff0c;求小A集齐n种印章的概率。 输入格式 一行两个正整数n和m 输出格式 一个实数P表示答案&#xff0c;保留4位小数。 样例输入 2 3 样例输出 0.7500 数据规模和约定 1≤…

pytest之yaml格式测试用例读写封装

pytest之yaml格式测试用例读写封装 pytest之parametrize&#xff08;&#xff09;实现数据驱动YAML格式测试用例读/写/清除/封装结构类型Maps类型数组类型 pytestparametrizeyamltest_api.pyget_token.yaml pytest之parametrize&#xff08;&#xff09;实现数据驱动 pytest.ma…

LeetCode_32_困难_最长有效括号

文章目录 1. 题目2. 思路及代码实现详解&#xff08;Java&#xff09;2.1 动态规划2.2 不需要额外空间的算法 1. 题目 给你一个只包含 ( 和 ) 的字符串&#xff0c;找出最长有效&#xff08;格式正确且连续&#xff09;括号 子串 的长度。 示例 1&#xff1a; 输入&#xff…

Oracle Data Guard常用命令

--查询数据库角色和保护模式 select database_role,switchover_status from v$database; --切换备库为主库&#xff08;切换后&#xff0c;主库为mount状态&#xff09; --TO PRIMARY alter database commit to switchover to primary; --SESSIONS ACTIVE alter database comm…

springcloud+nacos服务注册与发现

快速开始 | Spring Cloud Alibaba 参考官方快速开始教程写的&#xff0c;主要注意引用的包是否正确。 这里是用的2022.0.0.0-RC2版本的springCloud&#xff0c;所以需要安装jdk21&#xff0c;参考上一个文章自行安装。 nacos-config实现配置中心功能-CSDN博客 将nacos-conf…

Head First Design Patterns -模板方法模式

什么是模板方法模式 在一个方法中定义一个算法的骨架&#xff0c;而把一些步骤延迟到子类。模板方法使得子类可以在不改变算法结构的情况下&#xff0c;重新定义算法的某些步骤。 这些算法步骤中的一个或者多个被定义为抽象的&#xff0c;由子类实现。 类图 代码 书中用泡茶和…

C# 编程语言中访问修饰符(access modifiers)

C#访问修饰符 protected 访问修饰符&#xff1a;1. public 访问修饰符&#xff1a;2. private 访问修饰符&#xff1a;3. internal 访问修饰符&#xff1a;4. protected internal 访问修饰符&#xff1a; 在 C# 编程语言中&#xff0c;有多个访问修饰符&#xff08;access modi…

kotlin中使用myibatis-plus的lambdaQuery的问题

kotlin中使用myibatis-plus的lambdaQuery的问题 代码&#xff1a;lambdaQuery().eq(User::username, username).one()报错&#xff1a;org.apache.ibatis.reflection.ReflectionException: Error parsing property name register$lambda$0. Didnt start with is, get or set.解…

#Linux(Samba安装)

&#xff08;一&#xff09;发行版&#xff1a;Ubuntu16.04.7 &#xff08;二&#xff09;记录&#xff1a; &#xff08;1&#xff09;键入命令安装Samba sudo apt-get install samba &#xff08;2&#xff09;修改samba配置文件 //打开配置文件 sudo vi /etc/samba/smb.…

Java基础-常用类

文章目录 1.Math类2.System类1.exit代码 结果2.arraycopy参数解释代码结果 3.currentTimeMillens代码结果 3.大数处理方案基本介绍BigInteger类介绍代码结果 BigDecimal类介绍代码结果 4.日期类对于IDEA类图中的属性![image-20240101190844530](https://img-blog.csdnimg.cn/im…