C++:traits,分类型处理

文章来自微信公众号“科文路”,欢迎关注、互动。转发须注明出处。

traits 在 MLIR 体系中被大量使用。它的本意很晦涩,“萃取信息”,有点像是隐含的重要信息。

简单讲,C++ 中的 traits 概念指代一种编程方法,它抽象一种接口,使得这个接口针对不同类型的输入作分别处理

技术本质上,traits 总被实现为一个类,插入接口和实现之间。

更多的,像 STL 中,就是用这些方法来实现了算法的类型无关的抽象。

下面一步步走近 traits。

1. template,推导参数类型

先看代码,

1
2
3
4
5
6
7
8
9
10
11
12
13
template <class I, class T> void func_impl(I iter, T t) {
T tmp; // 这里就是迭代器所指物的类型新建的对象
// ... 功能实现
}

template <class I> inline void func(I iter) {
func_impl(iter, *iter); // 传入iter和iter所指的值,class自动推导
}

int main() {
int i;
func(&i);
}

这是一段迭代器相关的代码。

在上述代码中,func(&i) 通过中间层 func_imp 自动推导出了 &i 所指向的数据类型,也就是 T

2. 偏特化,调整匹配顺序

偏特化其实就是在 (全)特化 啥都能传进去的模板类上,加了一些限制。例如下面的 <T *> 就使得这个类比上面的那个更 “特别”,这么做就能在遇到相应参数时得到优先的匹配权。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

template <class T> struct iterator_traits {
typedef typename T::value_type value_type;
};

template <class T> struct iterator_traits<T *> { typedef T value_type; };

template <class I> typename iterator_traits<I>::value_type func(I ite) {
return *ite;
}

int main() {
int a = 1;
std::cout << func(&a) << std::endl;
return 0;
}

从下往上看。

func 使用 I 时,I 将去匹配一个 iterator_traits。在这里,它将直接匹配到中间那个 <T *>,也就是偏特化的版本。

那么,当使用 func 函数的时候,传入的参数就得是 T *,否则报错。

所以最终得到的 value_typeT 而不是 I::value_type,这也就实现了文章开头所说的同样的接口,不同的处理

3. 回过头来,一个例子

下面这个例子体现了 traits 的作用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <vector>

template <class T> struct iterator_traits {
typedef typename T::value_type value_type;
};

template <class T> struct iterator_traits<T *> { typedef T value_type; };

void func(int a) { std::cout << "func(int) is called" << std::endl; }

void func(double a) { std::cout << "func(double) is called" << std::endl; }

void func(char a) { std::cout << "func(char) is called" << std::endl; }

int main() {
iterator_traits<std::vector<int>::iterator>::value_type a;
func(a); // 输出 func(int) is called

iterator_traits<std::vector<double>::iterator>::value_type b;
func(b); // 输出 func(double) is called

iterator_traits<char *>::value_type c;
func(c); // 输出 func(char) is called
return 0;
}

好了,就是这样,虽然看似复杂,其实实现的逻辑也没有那么难,对吧?

参考

都看到这儿了,不如关注每日推送的“科文路”、互动起来~

至少点个赞再走吧~

Author

xlindo

Posted on

2023-02-09

Updated on

2024-01-16

Licensed under

Comments