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

C++traits

traits

C++的标准库提供了<type_traits>,它定义了一些编译时基于模板类的接口用于查询、修改类型的特征:输入的时类型,输出与该类型相关的属性
通过type_traits技术编译器可以回答一系列问题:它是否为数值类型?是否为函数对象?是不是指针?有没有构造函数?能不能拷贝构造等等
type_traits技术还能对类型进行变换,比如给定的类型任意T,能为这个类型添加const修饰符、添加引用或指针等。而这一切都发生在编译时,过程中没有任何运行时开销

判断类别

谓词命名以is_为前缀,通过访问静态成员常量value得到输出结果

static_assert(std::is_integral<int>::value);//true
static_assert(! std::is_integral<float>::value);//false
static_assert(std::is_floating_point<double>::value);//true
static_assert(std::is_class<struct Point>::value);//true
static_assert(!std::is_same<int , long>::value);//false

is_integral用来判断给定的类型是否为整数类型,使用尖括号将类型输出给这个trait,通过其成员valu来输出一个bool类型的结果
is_floating_point用来判断给定的类型是否为浮点类型
is_class用来判断给定的类型是否为class、struct定义的类型
is_same用来判断给定的两个类型是否为相同类型


对于一个type traits谓词的结果,标准库约定使用value常量来存储,C++17为其预定义了一系列模板,::value的访问方式能够用_v来代替

template <typename T>constexpr bool is_integral_v = is_integral<T>::value;
template <typename T>constexpr bool is_class_v = is_class<T>::value;

类型变换

标准库有些typed traits拥有修改类型的能力:基于已有类型应用修改得到新的类型,输出类型可以通过访问type类型成员函数得到结果。

类型修改不会原地修改输入的类型,而是产生新的类型以应用这些修改

static_assert(is_same_v<typename std::remove_const<const int>::type , int>);
static_assert(is_same_v<typename std::remove_const<int>::type , int>);
static_assert(is_same_v<typename std::add_const<int>::type ,const int>);
static_assert(is_same_v<typename std::add_pointer<int **>::type , int ***>);
static_assert(is_same_v<typename std::decay<int[5][6]>::type , int(*)[6]>);

remove_const将输入的类型移除掉const修饰符并返回新的类型,如果不带const则不变
add_const将输入的类型添加const修饰符
add_pointer为输入的类型添加一级指针
decay语义为退化通过模拟函数或值语义传递时会使所有应用到的函数参数类型退化,若为引用那么应用将会去掉


在C++11引入类型别名using后typename decay<int[5] [6]>::type可变为decay_t<int[5] [6]>
下面是标准库定义的一些类型别名

template<typename T>using remove_const_t = typename remove_const<T>::type;
template<typename T>using decay_t = typename decay<T>::type;

辅助类

辅助类integral_constant将值与对应的类型包裹起来,从而能够将值转化为类型,也能从类型转换回值,实现值与类型的一一映射关系
这个类的主要作用是作为一个容器,用于存储在编译时就可以确定的值,并且这个值的类型也是在编译期可知的。

using Two = std::integral_constant<int,2>;
using Four = std::integral_constant<int,4>;
static_assert(Two::value * Two::value == Four::value);

Tow和Four为两个类型,分别对应2,4。使用integral_constant将值转换成类型后通过value静态成员常量从类型中得到值并进行计算


标准库对应布尔类型也提供了bool_constant,实现时仅仅是integral_constant的类型别名

template<bool v>using bool_constant = integral_constant<bool , v>;

将这两个值映射成类型

uaing true_type = integral_constant<bool , true>;
uaing false_type = integral_constant<bool , false>;

enable_if

enable_if常出现于SFINAE场景中,通过对模板函数,模板类中的类型进行谓词判断,使得程序能够选择合适的模板函数的重载版本或模板类的特化版本
enable_if可接受两个模板参数,第一个参数为bool类型的值,当条件为真时输出的类型成员type的结果为第二个模板参数,否则没有类型成员type

int a;
typename std::enable_if<a == 1,int>::type *a;  //当a==1时,condition为true,那么type为int,所以会声明一个int* a;
typename std::enable_if<!(a == 1),double>::type *a;  //a !=1时,condition为true,那么type为double,所以会声明一个double* a;

enable_if用于函数模板中,典型应用是作为函数模板的返回类型

template<typename T>
typename std::enable_if<(sizeof(T) > 2)>::type funceb()
{//....
}
nmsp2::funceb<int>();//void funceb(){}
nmsp2::funceb<char>();//error:未找到匹配的重载函数,条件不满足//C++14出了这个等同上面
template<typename T>
std::enable_if_t<(sizeof(T) > 2),T> funceb()
{T myt = {};return myt;
}nmsp2::funceb<int>();//int funceb(){}
//nmsp2::funceb<char>();

traits使用示例

  • 类型推断
#include <iostream>
#include <type_traits>template<typename T>
void print_type_trait(T value) {// 使用std::integral_constant作为编译时的常量表达式容器using TraitType = std::integral_constant<bool, std::is_integral<T>::value>;// 使用if constexpr语句在编译期决定是否打印信息if constexpr (TraitType::value) {std::cout << "The type of the variable is integral: " << typeid(T).name() << '\n';} else {std::cout << "The type of the variable is not integral: " << typeid(T).name() << '\n';}
}int main() {int integer = 10;double floating = 3.14;print_type_trait(integer); // 输出:"The type of the variable is integral"print_type_trait(floating); // 输出:"The type of the variable is not integral"return 0;
}
  • 模板函数
template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value>::type
print_sum(T a, T b) {std::cout << "Sum of arithmetic types: " << a + b << '\n';
}template<typename T>
typename std::enable_if<!std::is_arithmetic<T>::value>::type
print_sum(T a, T b) {std::cout << "Sum operation not supported for non-arithmetic types.\n";
}struct NonArithmetic {};int main() {print_sum(3, 5); // 输出:"Sum of arithmetic types: 8"print_sum("Hello", "World"); // 不会被实例化,因为std::string不是算术类型print_sum(NonArithmetic{}, NonArithmetic{}); // 输出:"Sum operation not supported for non-arithmetic types."return 0;
}

http://www.lryc.cn/news/340032.html

相关文章:

  • gitee和idea集成
  • 阿维·威格德森(Avi Wigderson)研究成果对人工智能领域的应用有哪些影响
  • 【免费领取源码】可直接复用的医院管理系统!
  • leetcode代码记录(全排列 II
  • 【数据结构与算法】之双向链表及其实现!
  • 记一次奇妙的某个edu渗透测试
  • 设计模式学习笔记 - 设计模式与范式 -总结:1.回顾23中设计模式的原理、背后的思想、应用场景等
  • 22 文件系统
  • OVITO-2.9版本
  • 【Java开发指南 | 第一篇】类、对象基础概念及Java特征
  • Neo4j 图形数据库中有哪些构建块?
  • 002 springboot整合mybatis-plus
  • 代码随想录训练营第三十五期|第天16|二叉树part03|104.二叉树的最大深度 ● 111.二叉树的最小深度● 222.完全二叉树的节点个数
  • Mac版2024 CleanMyMac X 4.15.2 核心功能详解 cleanmymac这个软件怎么样?cleanmymac到底好不好用?
  • 【华为OD机试】执行任务赚积分【C卷|100分】
  • mybatis分页实现总结
  • Vue3——html-doc-js(html导出为word的js库)
  • 第19天:信息打点-小程序应用解包反编译动态调试抓包静态分析源码架构
  • 外观模式:简化复杂系统的统一接口
  • PHP数组去重
  • 论软件系统的架构风格,使用三段论 写一篇系统架构师论文
  • 深度挖掘响应式模式的潜力,从而精准优化AI与机器学习项目的运行效能,引领技术革新潮流
  • 企业级网络安全:入侵防御实时阻止,守护您的业务安全
  • (一)Java八股——Redis
  • 2024.4.15力扣每日一题——设计哈希映射
  • 数据结构DAY4--哈希表
  • MySQL二阶段和三阶段提交
  • 代码随想录算法训练营第四十二天|01背包问题、416. 分割等和子集
  • JVM主要知识点详解
  • hot100 -- 链表(中)