STL基础(一)简单模板函数、模板类以及模板实例化

本文详细介绍了C++中的模板函数max的使用,区分了显式实例化和隐式实例化的概念,并通过实例演示了如何在模板类Box中应用这两种实例化方式。
摘要由CSDN通过智能技术生成

1、简单模板函数

先看一个简单的模板函数max,它接受两个类型为T的参数,并且返回类型为T的结果,用它可以比较两个整数、浮点数,或者是支持>运算符的类型之间的最大值:

	template <typename T>
	T max(T a, T b) {
		return a > b ? a : b;
	}

下面是如何使用这个模板的例子:

void TestSimpleTemplete() {
	std::cout << MyTemplate::max<int>(10, 20) << std::endl;
	std::cout << MyTemplate::max<double>(3.14, 5.22) << std::endl;
	std::cout << MyTemplate::max<char>('a', 'b') << std::endl;

	class InnerData {
	public:
		InnerData(int x) :val(x) {}
		bool operator>(InnerData &other) {
			return this->val > other.val;
		}
		int getVal() { return val; }
	private:
		int val;
	};
	std::cout << MyTemplate::max<InnerData>(InnerData(2), InnerData(3)).getVal() << std::endl;
}
// output
// 20
// 5.22
// b
// 3

2、显式实例化与隐式实例化

接下来我们要引出实例化的概念,实例化指的是编译器根据给定的模板参数创建函数或者类型的过程,简单来说就是编译器确认模板类型。

以上述max函数为例,我们使用时指定模板参数为int,就是MyTemplate::max<int>模板实例化过程,我们人为/主动指定参数为int的动作被称为显式实例化

对应的还有隐式实例化,我们不需要传递具体类型,编译器编译时会为我们自动推断模板参数的类型。

使用隐式实例化同样可以获得预期的结果:

void TestSimpleTemplete() {
    std::cout << MyTemplate::max(10, 20) << std::endl;
	std::cout << MyTemplate::max(3.14, 5.22) << std::endl;
	std::cout << MyTemplate::max('a', 'b') << std::endl;
	std::cout << MyTemplate::max(InnerData(2), InnerData(3)).getVal() << std::endl;
}
// output
// 20
// 5.22
// b
// 3

什么时候用显式实例化,什么时候用隐式实例化呢?

使用隐式实例化时,我们希望模板参数类型可以直接通过上下文来推导,这是比较推荐的方式;如果编译器无法自动推导出模板参数类型,或者是我们希望显式地指定一个不同的类型,这时候我们要用显式实例化。接下来我们举例来说明:

如果我们想用max比较一个int和一个double类型,用隐式实例化的方法去写,在编译时会产生error,提示没有与参数列表匹配的函数模板,实例参数类型为(int, double)

    // error
    std::cout << MyTemplate::max(10, 2.1) << std::endl;  // error example

但是我们目的就是想要比较这两个值要怎么做呢?我们需要显式实例化,指定模板类型:

	std::cout << MyTemplate::max<int>(1, 2.1) << std::endl;		// 2
	std::cout << MyTemplate::max<double>(1, 2.1) << std::endl;	// 2.1

要注意的是,指定的类型不同返回的结果也会不同。

另一种情况,在参数为2个double时,用隐式实例化编译器会帮自动推导类型为double,但是我们偏要使用int来处理,这时候就要用显式实例化。

    std::cout << MyTemplate::max<int>(1.1, 2.1) << std::endl;	// 2

从上面的例子中我们可以了解到,一般来说使用隐式实例化让模板自动推导即可;如果编译器无法推导,或者是希望覆盖自动推导结果时,我们可以使用显式实例化

注意!隐式/显式实例化针对的是模板函数,模板类并没有隐式实例化的说法!

3、简单模板类

以下是一个简单的模板类,示例中展现了模板类方法的类内以及类外两种实现方式:

	template <typename T>
	class Box {
	public:
		Box() :pointer(0) {}
		void push(T elem);
		void pop() {
			if (pointer > 0) {
				std::cout << "pop [" << arr[pointer-1] << "] ok" << std::endl;
				--pointer;
			} else {
				std::cout << "pop fail, no element" << std::endl;
			}
		}
	private:
		T arr[100];
		int pointer;
	};

	template <typename T>
	void Box<T>::push(T elem) {
		if (pointer <= 99) {
			std::cout << "push [" << elem << "] ok" << std::endl;
			arr[pointer] = elem;
			++pointer;
		} else {
			std::cout << "push fail, no space" << std::endl;
		}
	}

模板类和模板函数的使用方法类似,不同的是模板类没有隐式实例化的说法,实例化时一定要显式指定类型参数:

void TestSimpleTempleteClass() {
	MyTemplate::Box<int> ibox;
	ibox.push(1);
	ibox.push(2);
	ibox.pop();

	MyTemplate::Box<double> dbox;
	dbox.push(1.1);
	dbox.push(2.2);
	dbox.pop();
	dbox.pop();
}

普通类的方法实现一般会放到cpp文件当中,但是模板类的方法实现必须要放在头文件当中。这是因为模板不是普通代码,它们是编译器用来生成特点类型代码的一种工具,编译器需要看到完整的模板定义才能在使用模板的源文件中生成对应的代码实例。

如果把模板类的实现放在cpp文件中,那么其他cpp文件会无法看到这些实现代码,编译器也就无法生成对应的类实例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青山渺渺

感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值