CPP模板中的trait思想[CPP template-6]

本节内容是作者读CPP template经典《C++ Templates》(美· David vandevoorde 德· Nicolai M·Josuttis 著)第三部分 模板和设计 第15章的笔记(也可以算读后感吧),经典不愧是经典,读来真是发人深省,今笔录之,与诸君共赏,也做CPP template的第6节-----基本操作 24/8/4

trait:类型的函数

trait 这个英文翻译成中文,是特征的涵义,我们可以从这里窥见一二它在模板中起什么作用。trait是一种CPP程序设计机制,是的,它并不是一个具体的函数,或者类什么的,它是程序专家Nathan提出的一个概念,并且Nathan把它严格化,把这种思想提交给了C++标准委员会(在Nathan的叫法中trait不叫trait,而是叫baggage template)。后来C++程序员们发现,欸,这玩意怪好用,所有trait思想的代码在CPP中很常见。下面我们一起来学习一下
在笔者看来,简单来说,trait是“类型的函数“,类比函数,输入一个值,输出一个值,类型的函数关键思想就一个”输入一个类型,就输出一个(或者多个)类型

从累加说起

累加一个序列是相当常见的任务,如果是其他的编程语言,我们要一个个写对于不同类型的累加函数,但是对于CPP,我们下面使用模板,写到这里,程序员想着:只要有实例化,编译器就会给我们完成我们期望的”任意类型的累加函数“…是这样吗?

#include <iostream>

using namespace std;

template <typename T>
inline T accum(T const* beg, T const* end)
{
	T total = T();
	//T()对于内建类型总是生成0值
	//注意,出问题的区域就是这里,我们用一个和输入的值的同类型的0值去存储总和,这比较危险
	while (beg != end)
	{
		total += *beg;
		++beg;
	}
	return total;
}

int main()
{
	int num[] = { 1,2,3,4,5 };
	cout << accum(&num[0], &num[5]) / 5 << endl;

	char name[] = "templates";
	int length = sizeof(num,name) - 1;
	//逗号运算符只会计算最后一个值
	cout << "length:" << length << endl;
	cout << accum(&name[0], &name[length]) / length << endl;

	return 0;
}

看上去很不错,对吧?但是运行后的结果呢?

3
length:9
-5

好像不太对啊(;′⌒`)。char的值总是大于0的,为什么这个字符串的平均值会是-5?很简单,发生了溢出。char的最大值是127,在累加过程中,值很轻易的超过了127,进而到达负数区(关于计算机如何存储整型的,我在前面的文章里写过了),所以你计算出来是负数。果然,有些时候想省精力,结果会搞出额外的问题。看来我们需要一个类型函数,如果输入一个类型,就给出我们希望的指定类型,比如这里,我们输入char类型,给出int类型,那累加基本就不会溢出了

Traits

下面我们来看看如何简单的使用模板来实现类型的函数

//统一模板,提供最大的匹配
template <typename T>
struct AccumTraits;

// 下面是特化的模板
// 下面我们根据匹配原则来指定元素配对
template<>
struct AccumTraits<char>
{
	using ACCT = int;
};

template<>
struct AccumTraits<int>
{
	using ACCT = long;
};

template<>
struct AccumTraits<unsigned int>
{
	using ACCT =unsigned long;
};

template<>
struct AccumTraits<float>
{
	using ACCT = double;
};

template <typename T>
inline
typename AccumTraits<T>::ACCT              //返回值单写一行,typename用于告诉编译器这是类型
accum(T const* beg, T const* end)
{
	using type = typename AccumTraits<T>::ACCT;//这里的typename也不能少
	type total = type();
	while (beg != end)
	{
		total += *beg;
		++beg;
	}
	return total;
}

再运行一遍,这次就对了

3
length:9
108

value traits

也许你也注意到了,using type = typename AccumTraits<T>::ACCT;type total = type();这个语句不总是能生成出合适的0值(type类型不是总有一个合适的默认构造函数),但是延续上面的思路,我们很容易在AccumTraits中手动添加合适的0值对象,下面以char类型为例子,那么在求和函数中,你只需要调用这个zero就行。看来模板确实能大大减少CPP程序员的代码工作量

template<>
struct AccumTraits<char>
{
	using ACCT = int;
	static ACCT constexpr zero = 0;
    //你也可以使用一个返回0值的函数来完成这个任务
};
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值