从放弃到重启 C++泛型编程篇(1)—Traits

168 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

第一次接触到泛型还是 Java 语言,在 Java 中,学习到泛型概念,并用到到了泛型,当时泛型是放宽对类型的约束,是 MVP 设计模式下,通过行为将类进行从新划分为 type 这里可以将其理解 type 而不是 class ,可以将这里 type 理解为型别。

Traits

如何理解 Traits,如果我们直接抛出概念,因为这是一个比较抽象概念,大家理解起来可能不那么容易,这里还是通过一例子,也就是一个问题来引出 Traits,通常提出一个新的方法或者功能都是为了解决问题,我们来写一个算法,很简单就是求和算法,算法名字用 Sigma,因为函数比较简单,只是返回一个集合的所有元素相加的和,所以这里将函数定义为内联函数。然后通过一个模板来让算法可以接受各种类型作为参数。

#include<iostream>

using namespace std;

template <typename T> inline T Sigma(const T const* start, const T const* end)
{
	T total = T();
	while (start != end) {
		total += *start++;
	}

	return total;
}

注意: 如何构建类型为 T 的初始值 0,此处姑且使用 T(), 对于内置的类型,比如 int、float 等,初始值是 0

int main()
{
	int arr[] = { 1,2,3 };
	int res;

	res = Sigma<int>(arr, arr + 3);
	cout << res << endl;


	return 0;
}

接下来我们创建一个 char 数组的字符串,然后查看对字符进行求和,这里大家能过猜出 a b c 求和的结果。

char c[] ="abc";
size_t length = strlen(c);
char* p = c;
char* q = c + length;

printf("Sigma(c) = %d\n", Sigma<char>(p, q));

这里创建字符数组为 "abc" Char 类型能够保存 0xFF = 255 也就是 char 类型的能够表示取值范围为 255 。

字母aaa
979899

(97 + 98 + 99) = 294 这是应该得到结果,其原因是 Char 类型只能保持 255 大小,当试图保存 294 时,就发生了溢出,

为每个 Sigma 函数的参数类型为 T 创建一种关联(association) 关联的类型就是用来存储 Sigma 结果的类型,这种关联可以看作时类型 T 的一种特性(characteristic of the type T),因此 Sigma 函数返回值的类型叫做 T 的 trait,Traits 可以实现为模板类,而关联(association)则是针对每个具体类型 T 的特化,在这个例子里我们将 traits 命名为 SigmaTraits 叫做 traits 模板(trait template)。

template<typename T> class SigmaTraits{};
template <> class SigmaTraits<char> {
public: typedef int ReturnType;
};

template <> class SigmaTraits<int> {
public: typedef long ReturnType;
};

template <> class SigmaTraits<unsigned int> {
public: typedef unsigned long ReturnType;
};

template <> class SigmaTraits<float> {
public: typedef double ReturnType;
};

这里我们就用 Traits 将返回类型与某一个类型相关联,我们定义了一个类 SigmaTraits 这是一个模板类,然后当 T 指定为某一个类,然后为其定义一个特征,也就是将某一个类型与该类型进行关联。

No参数类型返回类型
1charint
2charlong
3unsigned intunsigned long
4floatdouble

template <typename T> 
inline typename SigmaTraits<T>::ReturnType Sigma(const T const* start, const T const* end)
{
	typedef typename SigmaTraits<T>::ReturnType ReturnType;
	ReturnType s = ReturnType();
	while (start != end) {
		s+= *start++;
	}

	return s;
}
  • 模版类 SigmaTraits 叫做 traits template, 含有其参数类型 T 的一个特性,也就是 ReturnType。返回都是 typename SigmaTraits::ReturnType,虽然传入参数 T 的类型是 char,但是返回的类型却是 int,原因就在于 template<> class SigmaTraits<char> 特化将类型 char 的返回值变成 int。