前言
说到C++模板,这个已经不是什么新东西了,自己在实际开发中也用过;对于C++模板特化和偏特化,对于别人来说,已经不是什么新东西了,但是对于我来说,的确是我的盲区,那天在群里讨论这个问题,自己对于这部分确实没有掌握,又联想到在《STL源码剖析》一书中,对于此也是有着介绍。所以,今天就对此进行详细的总结,以备后忘。
C++模板
说到C++模板特化与偏特化,就不得不简要的先说说C++中的模板。我们都知道,强类型的程序设计迫使我们为逻辑结构相同而具体数据类型不同的对象编写模式一致的代码,而无法抽取其中的共性,这样显然不利于程序的扩充和维护。C++模板就应运而生。C++的模板提供了对逻辑结构相同的数据对象通用行为的定义。这些模板运算对象的类型不是实际的数据类型,而是一种参数化的类型。C++中的模板分为类模板和函数模板。
类模板如下:
#include <iostream>
using namespace std;
template <class T>
class TClass
{
public:
// TClass的成员函数
private:
T DateMember;
};
函数模板如下:
template <class T>
T Max(const T a, const T b)
{
return a > b ? a : b;
}
模板特化
有时为了需要,针对特定的类型,需要对模板进行特化,也就是所谓的特殊处理。比如有以下的一段代码:
#include <iostream>
using namespace std;
template <class T>
class TClass
{
public:
bool Equal(const T& arg, const T& arg1);
};
template <class T>
bool TClass<T>::Equal(const T& arg, const T& arg1)
{
return (arg == arg1);
}
int main()
{
TClass<int> obj;
cout<<obj.Equal(2, 2)<<endl;
cout<<obj.Equal(2, 4)<<endl;
}
类里面就包括一个Equal方法,用来比较两个参数是否相等;上面的代码运行没有任何问题;但是,你有没有想过,在实际开发中是万万不能这样写的,对于float类型或者double的参数,绝对不能直接使用“==”符号进行判断。所以,对于float或者double类型,我们需要进行特殊处理,处理如下:
#include <iostream>
using namespace std;
template <class T>
class Compare
{
public:
bool IsEqual(const T& arg, const T& arg1);
};
// 已经不具有template的意思了,已经明确为float了
template <>
class Compare<float>
{
public:
bool IsEqual(const float& arg, const float& arg1);
};
// 已经不具有template的意思了,已经明确为double了
template <>
class Compare<double>
{
public:
bool IsEqual(const double& arg, const double& arg1);
};
template <class T>
bool Compare<T>::IsEqual(const T& arg, const T& arg1)
{
cout<<"Call Compare<T>::IsEqual"<<endl;
return (arg == arg1);
}
bool Compare<float>::IsEqual(const float& arg, const float& arg1)
{
cout<<"Call Compare<float>::IsEqual"<<endl;
return (abs(arg - arg1) < 10e-3);
}
bool Compare<double>::IsEqual(const double& arg, const double& arg1)
{
cout<<"Call Compare<double>::IsEqual"<<endl;
return (abs(arg - arg1) < 10e-6);
}
int main()
{
Compare<int> obj;
Compare<float> obj1;
Compare<double> obj2;
cout<<obj.IsEqual(2, 2)<<endl;
cout<<obj1.IsEqual(2.003, 2.002)<<endl;
cout<<obj2.IsEqual(3.000002, 3.0000021)<<endl;
}
模板偏特化
上面对模板的特化进行了总结。那模板的偏特化呢?所谓的偏特化是指提供另一份template定义式,而其本身仍为templatized;也就是说,针对template参数更进一步的条件限制所设计出来的一个特化版本。这种偏特化的应用在STL中是随处可见的。比如:
template <class _Iterator>
struct iterator_traits
{
typedef typename _Iterator::iterator_category iterator_category;
typedef typename _Iterator::value_type value_type;
typedef typename _Iterator::difference_type difference_type;
typedef typename _Iterator::pointer pointer;
typedef typename _Iterator::reference reference;
};
// specialize for _Tp*
template <class _Tp>
struct iterator_traits<_Tp*>
{
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef ptrdiff_t difference_type;
typedef _Tp* pointer;
typedef _Tp& reference;
};
// specialize for const _Tp*
template <class _Tp>
struct iterator_traits<const _Tp*>
{
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef ptrdiff_t difference_type;
typedef const _Tp* pointer;
typedef const _Tp& reference;
};
看了了么?这就是模板偏特化,与模板特化的区别在于,模板特化以后,实际上其本身已经不是templatized,而偏特化,仍然带有templatized。我们来看一个实际的例子:
#include <iostream>
using namespace std;
// 一般化设计
template <class T, class T1>
class TestClass
{
public:
TestClass()
{
cout<<"T, T1"<<endl;
}
};
// 针对普通指针的偏特化设计
template <class T, class T1>
class TestClass<T*, T1*>
{
public:
TestClass()
{
cout<<"T*, T1*"<<endl;
}
};
// 针对const指针的偏特化设计
template <class T, class T1>
class TestClass<const T*, T1*>
{
public:
TestClass()
{
cout<<"const T*, T1*"<<endl;
}
};
int main()
{
TestClass<int, char> obj;
TestClass<int *, char *> obj1;
TestClass<const int *, char *> obj2;
return 0;
}
对于输出结果,我这里就不写了,大家可以试一试。
特化与偏特化的调用顺序
对于模板、模板的特化和模板的偏特化都存在的情况下,编译器在编译阶段进行匹配时,是如何抉择的呢?从哲学的角度来说,应该先照顾最特殊的,然后才是次特殊的,最后才是最普通的。编译器进行抉择也是尊从的这个道理。从上面的例子中,我们也可以看的出来,这就就不再举例说明。
总结
对于模板的特化和偏特化,我的理解可能也不是很正确。希望大家和我进行探讨。我这里只是对自己的一些理解进行了总结。最后,也希望大家对我的博客提出中肯的建议。我坚信,分享使我们更进步。
相关推荐
模板特化有时也称之为模板的具体化,分别有函数模板特化和类模板特化。 1.2函数模板特化 函数模板特化是在一个统一的函数模板不能在所有类型实例下正常工作时,需要定义类型参数在实例化为特定类型时函数模板的特定...
一、类模板全特化、偏特化 #pragma once #include #include template class TC { public: TC() { std::cout << "泛化版本构造函数" < class TC { public: TC() { std::cout << "全特化版本...
模板的 主版本模板类、全特化、偏特化
C++模板特化匹配规则
说起C++的模板及模板特化, 相信很多人都很熟悉,但是说到模板特化的几种类型, 相信了解的人就不是很多。我这里归纳了针对一个模板参数的类模板特化的几种类型, 一 是特化为绝对类型; 二是特化为引用,指针类型;...
泛型容器的设计实现大多只是存储了类型的单个对象,而没有存储类型的多个对象,如果有这样特定的需求,容器内的元素要求都是某个类型的多个对象,那么这时就可以考虑用模板类的数组特化来实现了
C++模板类型题型,更全面,也可以更从中了解模板的运用与技术。
函数模板完全特化 C++ Builder 示例 代码参考: 余文溪的《C++ STL --数据结构与算法实现》原书代码为控制台。 这里用 C++ Builder代码演示
模板编程中如果要特化或偏特化(局部特化)一个类模板,需要特化该类模板的所有成员函数。类模板中大多数成员函数的功能可能是一模一样的,特化时我们可能只需要重新实现1、2个成员函数即可。在这种情况下,如果全部...
本文学习自 狄泰软件学院 唐佐林老师的 C++课程,文中图片源自老师课程PPT。 实验1:类模板的特化 实验2:特化的深入理解:函数模板的完全特化 实验1:类模板的特化 #include #include using namespace std; ...
编译环境: Windows 7 Service Pack 1 C++ Builder Embarcadero RAD Studio XE Version 15.0.3890.34076 ... 余文溪的《C++ STL --数据结构与算法实现》原书代码为控制台。 这里用 C++ Builder代码演示
我们知道在C++模板编程中如果我们特化或是偏特化某个模板类, 我们需要重写整个模板类中的所有函数, 但是这些代码通常是非常相似的, 甚至在某些情况下可能只有一两个函数会不一样,其他函数都是一样的。...
C++模板学习记录 模板定义 模板使用 类模板 函数模板 特化模板 编译器
利用模板特化机制实现编译期条件选择结构,利用递归模板实现编译期循环结构,模板元程序则由编译器在编译期解释执行。通过将计算从运行期转移至编译期,在结果程序启动之前做尽可能多的工作,最终获得速度更快的程序...
LuaMe后期版本,早期版本看我早起上传的资源。主要是优化了部分代码,支持在lua端申请结构体了,并且利用lua的垃圾回收处理内存。多处使用了条件编译,可以利用条件编译出不同特性的结构体(具体使用参考其中的代码...
模板的“特化”(实例化),它发生在编译期,无论一个模板被实例化多少次,都不会影响最终结果,但是这会浪费编译的时间.不知道隐式特化是啥东西.但是显式特化的意思是:当一类东西中出了一渣滓的时候,为了对外接口的...