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

初尝类型萃取--typename、模板偏特化、和traits之(三)类型萃取

目录

当模板遇到迭代器和指针

类型萃取是如何解决上述问题的


本文作者在看过公众号《C++学习与探索》的文章《【一分钟学习C++】萃取机制》后,对类型萃取(type_traits)有了初步的认识,所以写下这篇博客。《【一分钟学习C++】萃取机制》门槛较高,如果没有理解typename和模板偏特化,是难以理解该文意思的。本文以及前面的两篇文章(初尝类型萃取--typename、模板偏特化、和traits之一、二)目的是将萃取涉及的基本知识点,如typename、模板偏特化先讲清楚,然后通过讲解例子的方式,使得类型萃取能被更多读者理解。

当模板遇到迭代器和指针

看下面例子:

#include <iostream>template <typename T>
class tmp
{
public:*T ret(T s) {//编译失败,用auto代替*T是可以的return *s;}
};
int main()
{int p = 1;tmp<int*> t;int i = t.ret(&p);std::cout << "i = "<<i<<"\n";return 0;
}

在C++标准里,你可以用*指针 的方式获取一个变量,但是不能用*类型。上面的例子使用*T是失败的。

同样,使用迭代器也有类似的问题:

#include <vector>
#include <iostream>template <typename T>
class tmp
{
public:*T ret(T s) {//编译同样失败return *s;}
};
int main()
{std::vector<int> vec{ 0,1,2 };std::vector<int>::iterator itr = vec.begin();tmp< std::vector<int>::iterator> t;int i = t.ret(itr);std::cout << "i = "<<i<<"\n";return 0;
}

正如前面所说,在C++标准里,你可以用*指针 的方式获取一个变量,但是不能用*类型。我们可以用auto替代*T的写法。另外,我们也可以采用萃取技术。

类型萃取是如何解决上述问题的

类型萃取主要依赖两个技巧:

1 使用typename

2 模板偏特化

看下面的代码:

#include <type_traits>
#include <iostream>//先准备非特化的模板
template <typename T>
struct itr_trait;
//特化模板
template <typename T>
struct itr_trait<T*>
{//using valuetype = T;//等效于下面的typedef typename T valuetype;itr_trait(T * t) {i = *t;s = t;}valuetype i;valuetype* s;valuetype getS() { return *s; }
};int main()
{int a = 2;itr_trait<int *> t(&a);std::cout <<"i = "<<t.i << ",*s = "<<*t.s<<",t.s is int * "<<(std::is_same<int*, decltype(t.s)>::value ? std::string("true") : std::string("false")) << std::endl;std::cout << "getS() = " << t.getS() << std::endl;std::cin.get();return 0;
}

main函数中的itr_trait<int *>匹配了特化模板itr_trait<T *>。所以T = int。

由于typedef typename T valuetype这句,valuetype = T = int

由于valuetype * s这句,s的类型就是int *

getS()的返回值就是int。这样也就解决了文章开头* T编译失败的问题。

再来看看《【一分钟学习C++】萃取机制》里面更加复杂的示例:

// class type
template <class T>
struct iterator_traits {//用来处理迭代器的情况typedef typename T::value_type value_type;//迭代器T一定含有T::value_type这个类型
};
// 指针类型偏特化,用来处理指针的情况
template <class T>
struct iterator_traits<T*> {typedef T value_type;
};
// const指针类型偏特化,用来处理指针的情况
template <class T>
struct iterator_traits<const T*> {typedef T value_type;
};template <class T>
typename iterator_traits<T>::value_type//这定义func函数的返回值类型
func(T iter) {std::cout << "normal version" << std::endl;return *iter;
}

根据cppreference的说法std::iterator一定含有value_type这个成员。

在下面的例子里,T = vector<int>::iterator。func(T iter)里面的T是迭代器(而不是指针) ,则模板匹配非特化的情况。此时,由于

typedef typename T::value_type value_type;

iterator_traits<T>::value_type就等于vector<int>::iterator的value_type(value_type一定是iterator的成员),也就是int

// class type
template <class T>
struct iterator_traits {//用来处理迭代器的情况typedef typename T::value_type value_type;//迭代器T一定含有T::value_type这个类型
};template <class T>
typename iterator_traits<T>::value_type//这定义func函数的返回值类型
func(T iter) {std::cout << "normal version" << std::endl;return *iter;
}vector<int> vec;
vector<int>::iterator itr = vec.begin();

所以func函数的返回值类型iterator_traits<T>::value_type一定是vector<int>::iterator的value_type,也就是int。

假如func(T iter)的T类型是指针int *,则非特化模板不能与之匹配,因为int *没有value_type成员,使得

typedef typename T::value_type value_type;

不成立。

这时,特化模板就起作用了。

// 指针类型偏特化,用来处理指针的情况
template <class T>
struct iterator_traits<T*> {typedef T value_type;
};
// const指针类型偏特化,用来处理指针的情况
template <class T>
struct iterator_traits<const T*> {typedef T value_type;
};template <class T>
typename iterator_traits<T>::value_type//这定义func函数的返回值类型
func(T iter) {std::cout << "normal version" << std::endl;return *iter;
}int w = 2;
func<int *>(&w);

 下面这句将强制给iterator_traits加上一个成员类型value_type,且value_type = T。

typedef T value_type;

于是func模板展开成了下述形式:


iterator_traits<int*>::value_type//这定义func函数的返回值类型
func(int * iter) {std::cout << "normal version" << std::endl;return *iter;
}

匹配了下面的模板:

template <class T>
struct iterator_traits<T*> {typedef T value_type;
};
//匹配为:
struct iterator_traits<int *>{typedef int value_type;
};

故func函数返回值仍然是int。


http://www.mrgr.cn/news/52551.html

相关文章:

  • [算法日常] 逆序对
  • 2024年了,视频生成模型离通用世界模拟器还有多大差距?SOTA模型全面评估
  • 单链表的定义
  • 数据结构 —— 链式二叉树(C语言讲解)
  • 【蓝队技能】【C2流量分析】MSFCSSliver
  • netron安装(windows linux)
  • VS2022如何查看dll的函数
  • 模型实战(27)之 YOLO11 推理、验证及训练自己的数据集
  • Java设计模式六大原则
  • 【Vue】Vue3.0 (十二)、watchEffect 和watch的区别及使用
  • FreeRTOS - 软件定时器
  • 机器学习——主要分类
  • 系统工程概述
  • 智能算力中心万卡GPU集群架构深度解析
  • 【人工智能】实验室GPU资源申请使用
  • AI+Xmind彻底解决你的思维导图
  • Python学生成绩管理系统在用户交互方面有哪些创新设计?
  • 除GOF23种设计模式之简单工厂模式
  • 微分几何-曲线论(曲线)
  • 探索Python中的多线程与多进程