码迷,mamicode.com
首页 > 编程语言 > 详细

C++模板

时间:2015-10-19 23:47:38      阅读:278      评论:0      收藏:0      [点我收藏+]

标签:

最近使用了c++模板,觉得非常强大,只是写起来需要掌握一点技巧。大部分模板都是直接把定义写在.h头文件,并且有些人还说这样做的原因是模板不支持分编译,可是以前的编译器对模板的支持不够好吧,但是现在完全可以。

环境:

win7 32旗舰版、VS2010 sp1

1、普通函数模板

define.h文件

1 template<typename T>
2 T GetString(int value);

define.cpp文件

 1 #include "define.h"
 2 
 3 template<typename T>
 4 T GetString<T>(int value)
 5 {
 6     return T(value);
 7 }
 8 
 9 //偏特化
10 template<>
11 string GetString<string>(int value)
12 {
13     char psz[32] = {0};
14     itoa(value, psz, 10);
15     return string(psz);
16 }
17 
18 //偏特化
19 template<>
20 wstring GetString<wstring>(int value)
21 {
22     wchar_t psz[32] = {0};
23     _itow(value, psz, 10);
24     return wstring(psz);
25 }
如果我们直接包含define.h后,使用GetString<int>(100)函数调用,是使用不了的,会产生链接错误,为什么呢?我们上面定了函数模板的通用
实现,但是并没有实例化为一个真正的函数,既然不是函数,编译器当然不会生成代码,所以会出现链接错误;要解决这个问题的最主要就是实例化函
数模板使之成为一个真正的函数,第一种办法是:使用上面偏特化的方法,例如string和wstring类型的偏特化,因为上面已经写了,所以不多说了;
下面说第二种办法:
1 #define TEMPLATE_GET_STRING(T) template T GetString<T>(int value);
2 TEMPLATE_GET_STRING(int)//函数模板实例化
3 // 如果要在dll中导出此函数,我们可以这样
4 template __declspec(dllexport) int GetString<int>(int value);

2、类模板

define.h文件

 1 template<typename T>
 2 class A
 3 {
 4 public:
 5     A()
 6     {
 7         InitValue();
 8     }
 9 
10     void InitValue();
11 
12     int m_nValue;
13 };

define.cpp文件 

 1 template<typename T>
 2 A<T>::A()
 3 {
 4     InitValue();
 5 }
 6 
 7 template<>
 8 void A<string>::InitValue()
 9 {
10     m_nValue = 100;
11 }
12 
13 template<>
14 void A<int>::InitValue()
15 {
16     m_nValue = 200;
17 }
18 
19 // 类模板实例化
20 template
21 A<int>;

3、成员函数模板

define.h文件

1 class B
2 {
3 public:
4     template<typename T>
5     T Get(int index);
6 };

define.cpp文件

 1 //成员函数模板偏特化
 2 template<>
 3 double B::Get<double>(int index)
 4 {
 5     return 2.1;
 6 }
 7 
 8 //成员函数模板偏特化
 9 template<>
10 int B::Get<int><int>(int index)
11 {
12     return 1;
13 }
14 </int>
15 //如果类B是一个数据库封装类,我们就可以利用这样的调用方式来获取数据库一条记录中的字段
16 
17 B b;
18 b.Get<int>(1);//获取当前记录中第一个字段的值,并转化为int类型
19 b.Get<double>(2)//获取当前记录中第二个字段的值,并转化为double类型

4、将类型与一些数据进行绑定

有时候我们需要将类型与一些数据进行绑定,例如我们一般通过单例,将字符串与一个函数关联(注册),之后通过字符串创建对象

1 class A {
2 public:
3     static A* Create() { return new A(); }
4 };

然后像这样:

1 Instance::Register("A", A::Create);
2 A* a = Instance::Create("A");

用字符串进行绑定,不是很方便,如果字符串拼写错了,在整个编译期不会有任何提示,而且字符串是没有代码自动提示的,这样出错率大大增加了,当然你可以复制/粘贴;如果我们能够将一个类型与数据进行绑定,通过类型获取与之相关的数据,一是类型有代码自动提示的(一般拼写前几个字符就可以完成整个输入),及时你自己拼写出错了,没有定义这个类型,编译器编译时也会报错。

 1 typedef void*(*CreateCallback)(); // 创建函数的指针
 2 class Instance {
 3 public:
 4     /**   注册
 5      *    @T             绑定的类型
 6      *    @callback      对象创建函数
 7      */
 8     template<class T>
 9     static void Register(CreateCallback callback) {
10         m_map.insert(std::make_pair(TypeDefine<T>, callback));
11     }
12     
13     /**   创建对象
14      *    @T            创建对象的类型
15      *    @return       创建的对象
16      */
17     template<class T>
18     static T* Create() {
19         std::map<TypeDefineIndifiry, CreateCallback>::iterator iter = m_map.find(TypeDefine<T>);
20         return (T*)iter->second();
21     }
22 
23 private:
24     template<class T>
25     static void TypeDefine() {}
26 
27     typedef void(*TypeDefineIndifiry)();
28     static std::map<TypeDefineIndifiry, CreateCallback> m_map;
29 };
30 std::map<Instance::TypeDefineIndifiry, CreateCallback> Instance::m_map;

接下来我们使用它:

1 Instance::Register<A>((CreateCallback)A::Create);
2 A* a = Instance::Create<A>();

 

C++模板

标签:

原文地址:http://www.cnblogs.com/dongc/p/4893052.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!