type_traits

2023-11-16

 

概述

type_traits提供了丰富的编译期间计算、查询、判断、转换和选择的帮助类,其被定义在#include <type_traits>下。

作用:

  • 增强了泛型编程能力;
  • 增强程序的弹性,使得在编译期间就可以做到优化、改进甚至排错,提高代码质量;
  • 它所提供的选择功能一定程度上可以消除冗长的if-else或switch-case语句,降低程序的圈复杂度,提高代码的可维护性;
  • 它所提供的判断功能,在编译期间可以检查出是否是正确的类型,以便能编写更为安全的代码。

 

  • Helper Class

作用: 帮助创建编译时常量的标准类。

在C++11之前我们定义编译期常量的方法:

1.  通过定义静态变量,并通过CompileTimeContents::value方式获取该常量。

    template<typename Type>
    struct CompileTimeContents{
        static const int value = 1;
    };

2.  通过定义枚举变量方式。

    template<typename Type>
    struct CompileTimeContents{
       enum {value = 1};
    };

但在C++11中可以通过std::integral_constant 模版类派生:

    template<typename Type>
    struct CompileTimeContents :std::integral_constant<int, 1>
    {
    };

通过CompileTimeContents<type_name>::value方式获取该常量,这种写法好处是不用再定义额外变量,使用起来更加方便。

在标准库中的定义:

    template <class T, T v>
    struct integral_constant {
      static constexpr T value = v;
      typedef T value_type;
      typedef integral_constant<T,v> type;
      constexpr operator T() { return v; }
    };

 

  • 判断类型

在traits中判断类型的模板类 都 继承自 std::integral_constant

1.  判断目标类型是否为期望类型。

traits判断类型(下表展示部分,其他可到 http://www.cplusplus.com/reference/type_traits/ 查看):

traits类型 说明

is_array

判断是否为数组类型

is_class

判断是否为类类型而不是union类型

is_function

判断是否为函数类型

is_reference

判断是否为引用类型

is_pod

判断是否为POD(传统Cstruct类型)

is_trivial

判断是否为内置类型

使用实例:

// is_array example
#include <iostream>
#include <array>
#include <string>
#include <type_traits>

int main() {
  std::cout << std::boolalpha;
  std::cout << "is_array:" << std::endl;
  std::cout << "int: " << std::is_array<int>::value << std::endl;
  std::cout << "int[3]: " << std::is_array<int[3]>::value << std::endl;
  std::cout << "array<int,3>: " << std::is_array<std::array<int,3>>::value << std::endl;
  std::cout << "string: " << std::is_array<std::string>::value << std::endl;
  std::cout << "string[3]: " << std::is_array<std::string[3]>::value << std::endl;
  return 0;
}

运行结果:

判断类型通常会与std::enable_if结合使用,通过SFINAE(替换非错误)特性来实现功能更强的重载。

 

2.  判断两个模板类型之间的关系。

traits类型 说明
is_same 判断两个类是否相同
is_base_of 判断Base类型是否为Derivedl 类型的基类
is_convertible 判断前面模板参数类型能否转换为后面模板参数类型

 具体用法在官网依然有示例:

// is_base_of example
#include <iostream>
#include <type_traits>

struct A {};
struct B : A {};

int main() {
  std::cout << std::boolalpha;
  std::cout << "is_base_of:" << std::endl;
  std::cout << "int, int: " << std::is_base_of<int,int>::value << std::endl;
  std::cout << "A, A: " << std::is_base_of<A,A>::value << std::endl;
  std::cout << "A, B: " << std::is_base_of<A,B>::value << std::endl;
  std::cout << "A, const B: " << std::is_base_of<A,const B>::value << std::endl;
  std::cout << "A&, B&: " << std::is_base_of<A&,B&>::value << std::endl;
  std::cout << "B, A: " << std::is_base_of<B,A>::value << std::endl;
  return 0;
}

运行结果:

 

  • 类型转换

traits中给出了对参数属性的修改接口,如:其cv属性额添加或移除、引用的添加或移除、数组维度的修改等。

traits类型 说明
remove_cv 移除cv属性
add_cv 添加cv属性
remove_reference 移除引用
add_lvaue_reference 添加左值引用
remove_extent 移除数组顶层维度

示例:

// remove_cv example
#include <iostream>
#include <type_traits>

int main() {
  typedef const volatile char cvchar;
  std::remove_cv<cvchar>::type a;       // char a
  std::remove_cv<char* const>::type b;  // char* b
  std::remove_cv<const char*>::type c;  // const char* c (no changes)

  if (std::is_const<decltype(a)>::value)
    std::cout << "type of a is const" << std::endl;
  else
    std::cout << "type of a is not const" << std::endl;

  if (std::is_volatile<decltype(a)>::value)
    std::cout << "type of a is volatile" << std::endl;
  else
    std::cout << "type of a is not volatile" << std::endl;

  return 0;
}

运行结果:

 

  • 根据条件选择traits

std::conditional 在编译期间根据判断式选择两个类型中的一个,类似于常用的条件表达式。

template <bool Cond, class T, class F> struct conditional;

          当条件为真返回T类型,条件为假返回F类型。

例如:比较long long类型与long double 返回较大的类型

#include <iostream>
#include <typeinfo>
#include <type_traits>

int main() {
	typedef std::conditional<(sizeof(long long) > sizeof(long double)), \
		long long, long double > ::type max_size_t;
	std::cout << typeid(max_size_t).name() << std::endl;

	return 0;
}

运行结果:

 

  • 可调用对象返回值类型

通常我们获取函数返回值的类型使用的是decltype方式:

template<typename T, typename Arg>
auto Func(T a, Arg arg)->decltype(f(arg))
{
    return f(arg);
}

但是在某个类型没有模板参数时,就不能通过decltype来获取类型

#include <iostream>
#include <type_traits>

class A{
	A() = delete;

public:
	int operator()(int i){
		return i;
	}
};

int main() {
	// decltype(A()(0)) i = 4;
	decltype(std::declval<A>()(std::declval<int>())) i = 4;
	
	std::cout << typeid(decltype(std::declval<A>()(std::declval<int>()))).name() << std::endl;
	std::cout << i << std::endl;

	return 0;
}

当用仅用decltype方式获取类型时,由于A没有默认构造函数,代码出错。

之后采用declval方式,通过 declval<A>() 获取任意类型的临时值,但临时值不能用于求值,需要借助decltype对临时值进行类型推导,得出最终返回值。

在traits中提供了另一解决途径:std::result_of

	std::result_of<A(int)>::type i = 4;

函数原型: 

    // 第一个模板参数为可调用对象类型,第二个模板参数为参数类型
    template <class Fn, class... ArgTypes> 
    struct result_of<Fn(ArgTypes...)>;

 

  • ​​​​​​​根据条件禁用或启用某些类型

编译器在匹配重载函数时,通常匹配所有的重载函数,匹配一个如果失败了,编译器不会报错,而是接着匹配其他重载函数,选择最精确的一个去执行,整个过程不会报错(SFINAE)。

tratis中std::enable_if 根据限定条件选择重载函数,只对满足条件的函数有效。可作用于返回值、模板定义、类模板特化、参数类型限定。

函数原型:

    template <bool Cond, class T = void> 
    struct enable_if;

用法示例:

#include <iostream>
#include <type_traits>

// 1. 对函数返回值限定,只有模板参数T是integral类型时,才执行此函数
template <class T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
is_odd(T i) { return bool(i % 2); }


// 2. 对模板参数限定,模板特化时,模板参数只能是intergal类型
template < class T,
class = typename std::enable_if<std::is_integral<T>::value>::type>
	bool is_even(T i) { return !bool(i % 2); }


int main() {

	short int i = 1;    // code does not compile if type of i is not integral

	std::cout << std::boolalpha;
	std::cout << "i is odd: " << is_odd(i) << std::endl;
	std::cout << "i is even: " << is_even(i) << std::endl;

	return 0;
}

且通过编译期检查输入模板参数是否有效,来提前显示编译错误,避免运行时才被发现。

​​​​​​​

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

type_traits 的相关文章

随机推荐

  • anaconda虚拟环境python升级_Anaconda的安装与虚拟环境建立

    电脑配置 Windows10 64位操作系统 一 Anaconda的介绍 Anaconda指的是一个开源的Python发行版本 其包含了conda Python等180多个科学包及其依赖项 因为包含了大量的科学包 Anaconda 的下载文
  • 【LTspice】006 实际电容 阻抗特性曲线

    目录 1 电路图 2 仿真条件 3 电容元件选型 及 寄生参数 4 仿真结果分析 1 电路图 我们可以利用仿真软件的AC分析功能绘制电容的阻抗特性曲线 如下 放置一电容和电压源 设置如下图所示 2 仿真条件 AC 1 电压源指定小信号交流分
  • mysql日期相减操作

    一 MySQL中两个DateTime字段相减 假定表名为tblName 两个DateTime字段名分别为beginDateTime endDateTime 以下是相关两个mysql日期字段相减的SQL语句 这种方式两字段跨天 月 年都无问题
  • Android Studio教程从入门到精通

    转自 http blog csdn net yanbober article details 45306483 目标 Android Studio新手 gt 下载安装配置 gt 零基础入门 gt 基本使用 gt 调试技能 gt 构建项目基础
  • Journal of Proteome Research

    文献名 Lipidomics reveals similar changes in serum phospholipid signatures of overweight and obese paediatric subjects 用脂质组
  • pytorch1.13安装

    pytorch1 13安装 个人参考 情况交代 安装流程 注意事项 显卡配置查看 创建环境 激活环境 安装对应的torch版本 检查 使用pip list 导入查看 卸载 下载gpu版本的 验证 把这个内核加到jupyter 完成 情况交代
  • 挂载mount问题“wrong fs type, bad option, bad superblock on ”的解决办法

    重装系统后挂载一般会出现如下问题 problem ivy ivy OptiPlex 380 source sudo mount 192 168 9 18 home deep dev env source mount wrong fs typ
  • makefile进阶

    一 微观的C C 编译执行过程 c文件怎么变成可执行文件 exe 1 预处理 E 宏替换 头文件展开 去打印 gcc E hello c o hello i 2 编译 S 把 i 文件编译成汇编代码文件 i gcc S hello i o
  • 火星探险 (Mars)

    暂无链接 题目描述 在2051年 若干火星探险队探索了这颗红色行星的不同区域并且制作了这些区域的地图 现在 Baltic空间机构有一个雄心勃勃的计划 他们想制作一张整个行星的地图 为了考虑必要的工作 他们需要知道地图上已经存在的全部区域的大
  • canvas画布组件

    代码编写 在画布上添加各种几何图形 from tkinter import root Tk 设置主窗口区的背景顔色以区别画布区的顔色 root config bg 8DB6cD root title 基于tk的canvas几何图形 root
  • 附录2 高斯分布与马氏距离

    给定随机变量 xi i 1 N x i i 1
  • 深度学习优化器

    1 什么是优化器 优化器用来寻找模型的最优解 2 常见优化器 2 1 批量梯度下降法BGD Batch Gradient Descent 2 1 1 BGD表示 BGD 采用整个训练集的数据来计算 cost function 对参数的梯度
  • Vue技术 Object.defineProperty

    Object defineProperty 是JavaScript中的一个内置方法 用于定义或修改对象的属性 它接受三个参数 对象 属性名 以及一个属性描述符对象 属性描述符对象有两种形式 数据描述符和访问描述符 数据描述符用于定义普通属性
  • 【蓝桥杯】Java组必备API类 --快速读写实现方法 及输入输出的巧妙处理

    输入和输出 输入 Scanner s new Scanner System in 声明一个从控制台中读入数据的对象 int x s nextInt double x s nextDouble String x s next 无法读入空格 S
  • 统计和——前缀和

    题目大概 给定一个长度为n的整数数组和一个整数k 你需要找到该数组中和为k的连续子数组的个数 测试样例 输入 5 3 1 1 2 1 1 输出 2 思路1 利用for循环暴力枚举子数组 并且求和 计数 时间复杂度为O n 3 如果数据大于了
  • 毕设系列 - stm32机器视觉的口罩佩戴检测系统 - 单片机 物联网 嵌入式

    文章目录 0 前言 1 简介 2 主要器件 3 实现效果 4 设计原理 5 部分核心代码 6 最后 0 前言 这两年开始毕业设计和毕业答辩的要求和难度不断提升 传统的毕设题目缺少创新和亮点 往往达不到毕业答辩的要求 这两年不断有学弟学妹告诉
  • 桶排序 (详细图解)

    一 桶排序 桶排序 Bucket sort 或所谓的箱排序 是一个排序算法 工作的原理是将数组分到有限数量的桶里 每个桶再个别排序 有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序 最后依次把各个桶中的记录列出来记得到有序序列
  • 攻防世界web之ics-06

    打开网址 四处点击 点到报表中心 跳转新页面 查看源码也没有什么特别的 发现URL栏有 id 1 以为是sql注入 但是并不是 查看大佬的wp 发现这题采用brupsuite爆破 先将抓到的包放到Intruder 然后将id设为变量 然后把
  • WEB自动化测试面试题及答案大全

    1 Selenium是否支持桌面应用软件的自动化测试 Selenium不支持桌面软件的自动化测试 Selenium是根据网页元素的属性才定位元素 而其他桌面软件自动化测试工具是根据桌面元素的位置来定位元素 当然现在也有根据桌面元素的属性来定
  • type_traits

    概述 type traits提供了丰富的编译期间计算 查询 判断 转换和选择的帮助类 其被定义在 include