在动态库(dynamic libraries)和静态库(static libraries)使用模板(template)

板函数和模板类不能完全的支持动态导出库和静态库.


动态导入库和静态库: 他们实质是不一样的东西。静态库本身就包含了实际执行代码、符号表等等 ,而对于导入库而言,其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息 


问题分析: 模板函数和模板类在库中使用的时候 非常困难,但也不是不可能,因为只有相应参数类型的模板函数在库内部有实例,就能成功导出这个模板函数。对于模板类的公有成员函数们(包括构造/析构函数)全部都必须有实例存在。


为什么要将模板实例化: 只有将导出库里面的模板函数或者模板类实例化,才能将实例化后模板函数的地址信息和模板类实例化的地址信息保存在导出库中。


示范:我还是以一个例子来说明吧,这是个动态库(dynamic libraries)的例子。

//TemplateLib.h  使用动态库
#ifdef	TEST_DLL_EXPORTS
	#define	TEST_API	__declspec(dllexport)
#else
	#define TEST_API	__declspec(dllimport)
#endif


// 导出模板函数
template<typename T1>
TEST_API	void	fun1(T1);

template<typename T1,typename T2>
TEST_API	void	fun2(T1 , T2);


// 模板类
template<typename T,int size>
class TEST_API	CTest
{
public:
	CTest()		{};
	~CTest()	{};
	T*	GetDataBuff()	{	return m_data;}
private:
	T	m_data[size];
};

// TemplateLib.cpp : 定义 DLL 应用程序的导出函数。

#include "stdafx.h"
#include "TemplateLib.h"

// 1.利用重载来实例化不同类型的模板,代码量大不说,基本上是重复的代码
// 2.库的设计者不知道用户会传入什么类型,也就是说设计者不可能实例化每一种类型的模板。
TEST_API	void fun1(int var1)		{}

TEST_API	void fun1(char var1)		{}

template<typename T1,typename T2>
TEST_API	void fun2( T1 var1, T2 var2)	{}


// 这个名字空间不作为导出使用,唯一作用是用来例化函数模板和类模板.
namespace implement_template_private
{

	void	implement_template()
	{
		int		idata = 10;
		char	chr	= 'x';
		float	fdata = 20.f;
		UINT	undata= 9;
		char*	str	=	"hello";

		// 这种方式的实例化,代码量比重载方式少许多,但需运行一次该模板函数
		// 也许在某些时候凭空运行这个函数是不合理的。
		fun2(idata,chr);				// int,char
		fun2(undata,str);				// UINT,char*
		fun2<float,char*>(fdata,str);		// float,char* 显示参数

		// 导出类的实例化。
		// 1.除了要实例化提供给用户使用的公有成员函数外,这里面还隐含的实例化了构造函数和析构函数.
		// 2.注意这里每一个模板的实例化都是唯一的。
		// 3.假如客户如果在项目中使用了CTest<char,30> impl_obj; 将会连接错误, 模板的参数列表必须完全匹配。
		// 4.假如该模板类非常大,功能非常多,那么实例化工作可以想象是不堪忍受的。
		// 5.库的设计者不知道用户会传入什么类型,也就是说设计者不可能实例化每一种类型的模板。
		CTest<char,20>	impl_obj;
		impl_obj.GetDataBuff();


		CTest<int,5>	impl_obj2;
		impl_obj.GetDataBuff();
 
	}

};

//

在另外一个项目中使用我们刚刚创建的动态库


// TemplateExport.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "..\TemplateLib\TemplateLib.h"
#pragma comment(lib,"TemplateLib.lib")

int _tmain(int argc, _TCHAR* argv[])
{
	
	fun1<int>(10);
	fun1<char>('x');
	//fun1<float>(20.f);			// 连接错误

	fun2<float,char*>(20,"hello");
	//fun2<int,int>(20,30);			// 连接错误


	CTest<char,20> test;
	char* ret = test.GetDataBuff();

	//CTest<char,30> test2;		// 连接错误



	return 0;
}

范例下载地址: http://download.csdn.net/detail/xiexievv/4994974


总结与建议:不建议在导出库中使用模板相关的技术,假如你能够确定用户在使用你设计的模板函数时,将传入哪些类型(type),设计者要将这些类型的模板一 一实例化。


对模板比较感兴趣的同学还可以再看看这篇文章:

c++无类型参数模板(non-type template parameter)


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值