注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

(转载兼总结)全特化和偏特化  

2016-05-04 10:01:10|  分类: C++(VC)编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

 

(转载兼总结)全特化和偏特化

 

特化实现:实例化是一种特化方式;偏特化是一种;显示特化或者是全特化(全泛化-侯捷)是一种。

显示特化:应该是

实例化( Instantiation) 与特化( Specialization
template 中,「以实际值( actual values)做为 template arguments,从而产生常规的( regularclassfunction member function」,这个过程称为 「 template 实例化」( template instantiation)。
这 些 随 之 产 生 的 物 体(entity ;包 括 class, function member function ) 通 称为 特 化 体 ( specialization)。(
译注:我所阅读的众多泛型编程书籍中,很少将这些物体称为特化体,较 常称呼的是具现体, instantiation
C++ 中,实例化并非产生特化体的惟一方法。另一种机制可使程序员明白地以某些特
定的
template parameters 声明某些物体。我们在 3.3 , p.27 中已经介绍过这种方法:透过template<> 进行特化

explicit specialization(显式特化)
一种 C++构件,为某个
template 声明或定义一个替代性( alternative)定义式。最初的那个最泛化的 版本称为 primary template(主模板)。如果此一替代性定义仍需倚赖一或多个 template parameters, 它就被称为 partial specialization(偏特化),否则就称为 full specialization(全特化)。

instance(实体)
C++ 编程领域中, instance 有两层含义:面向对象方面的意思是 「某个 class 的实体」,也就是 object(对象),是某 class 的实现结果。例如C++ 中的 std::coutclass std::ostream的一个实体。
另一层意思(本书所采用)是 "a
template instance": 透过「以特定值替换所有 template parameters」而得到的 classesfunctions member functions。在这个意义下 instance 也被称为 specialization (特化体),后者常被误以为是 explicit specialization(显式特化体)。

显式实例化

这个一定要和显式特化区分开来。不要将二者混淆。在程序之中 , 每一个不同物体 ( distinct entity)最多只能有一份显式具现体 ( explicit instantiation)。所以显示实例化只能一次,OK。更详细的看“对特化的新的理解”和“模板的显示实例化和全特化”

特化/特化

http://www.360doc.com/content/12/1210/12/9200790_253182813.shtml

【转】全特化/偏特化

// general version
template<class T>
class Compare
{
public:
static bool IsEqual(const T& lh, const T& rh)
{
return lh == rh;
}
};

    这是一个用于比较的类模板,里面可以有多种用于比较的函数, 以IsEqual为例。

    一、特化为绝对类型

    也就是说直接为某个特定类型做特化,这是我们最常见的一种特化方式, 如特化float double

 // specialize for float
template<>
class Compare<float>
{
public:
static bool IsEqual(const float& lh, const float& rh)
{
return abs(lh - rh) < 10e-3;
}
};

// specialize for double
template<>
class Compare<double>
{
public:
static bool IsEqual(const double& lh, const double& rh)
{
return abs(lh - rh) < 10e-6;
}
};

    二、特化为引用,指针类型

    这种特化我最初是在stl源码的的iterator_traits特化中发现的, 如下:

 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;
};

    当然,除了T*, 我们也可以将T特化 const T* T& const T&等,以下还是以T*为例:

 // specialize for T* 
template<class T> 
class Compare<T*> 

public: 
static bool IsEqual(const T* lh, const T* rh) 

return Compare<T>::IsEqual(*lh, *rh); 

};

    这种特化其实是就不是一种绝对的特化, 它只是对类型做了某些限定,但仍然保留了其一定的模板性,这种特化给我们提供了极大的方便, 如这里, 我们就不需要对int* float* double*等等类型分别做特化了。

    三、特化为另外一个类模板

    这其实是第二种方式的扩展,其实也是对类型做了某种限定,而不是绝对化为某个具体类型,如下:

 // specialize for vector<T>
template<class T>
class Compare<vector<T> >
{
public:
static bool IsEqual(const vector<T>& lh, const vector<T>& rh)
{
if(lh.size() != rh.size()) return false;
else
{
for(int i = 0; i < lh.size(); ++i)
{
if(lh[i] != rh[i]) return false;
}
}
return true;
}
};

    这就把IsEqual的参数限定为一种vector类型, 但具体是vector<int>还是vector<float>, 我们可以不关心, 因为对于这两种类型,我们的处理方式是一样的,我们可以把这种方式称为特化

    当然, 我们可以将其特化为任何我们自定义的模板类类型:

 // specialize for any template class type
template <class T1>
struct SpecializedType
{
T1 x1;
T1 x2;
};
template <class T>
class Compare<SpecializedType<T> >
{
public:
static bool IsEqual(const SpecializedType<T>& lh, const SpecializedType<T>& rh)
{
return Compare<T>::IsEqual(lh.x1 + lh.x2, rh.x1 + rh.x2);
}
};

    这就是三种类型的模板特化, 我们可以这么使用这个Compare类:

 // int
int i1 = 10;
int i2 = 10;
bool r1 = Compare<int>::IsEqual(i1, i2);

// float
float f1 = 10;
float f2 = 10;
bool r2 = Compare<float>::IsEqual(f1, f2);

// double
double d1 = 10;
double d2 = 10;
bool r3 = Compare<double>::IsEqual(d1, d2);

// pointer
int* p1 = &i1;
int* p2 = &i2;
bool r4 = Compare<int*>::IsEqual(p1, p2);

// vector<T>
vector<int> v1;
v1.push_back(1);
v1.push_back(2);

vector<int> v2;
v2.push_back(1);
v2.push_back(2);
bool r5 = Compare<vector<int> >::IsEqual(v1, v2);

// custom template class
SpecializedType<float> s1 = {10.1f,10.2f};
SpecializedType<float> s2 = {10.3f,10.0f};
bool r6 = Compare<SpecializedType<float> >::IsEqual(s1, s2);

 

    模板有两种特化,全特化特化(局部特化

    模板函数只能全特化,没有特化(以后可能有)。

    模板类是可以全特化特化的。

    特化,就是模板中模板参数全被指定为确定的类型。

    特化也就是定义了一个全新的类型,全特化的类中的函数可以与模板类不一样。

    特化,就是模板中的模板参数没有被全部确定,需要编译器在编译时进行确定。

    在类型上加上const&* cosnt intint&int*、等等)并没有产生新的类型。只是类型被修饰了。模板在编译时,可以得到这些修饰信息。

    模板的特化是非常有用的。它像一个在编译期的条件判断。当编译器在编译时找到了符合的特化实现,就会使用这个特化实现。这就叫编译器多态(或者叫静态多态)。这种东西对编写基础库是很有用的。这也就是为何c++的基础库大量使用了模板技术,而且大量使用了特化,特别是特化

    在泛型中,利用特化类得到类新的特性,以便找到最适合这种特性的实现。而这一切都是在编译时完成。

 

 

 

 

http://blog.sina.com.cn/s/blog_997c255301012h6b.html

令人费解的偏特化 (2012-04-19 07:54:23)转载▼

标签: 杂谈  分类: Computer

偏特化是C++ 泛型(STL)中的一个技术,直到去年年底我才知道有这么个东西,觉得非常的神奇,不过想把它用上还真不是件容易的事情。

首先,什么是偏特化。在下面的代码中:

template<typename T, typename U>

inline T function(T a, U b) {

  return a * b;

}

 

template<typename T>

inline T function<T, int> (T a, int b) {

  return a * b;

}

function<T, int>即是对function的一个特化。当我们调用function(double, double)时,原function会被使用。但如果我们使用function(double, int)则会自动使用特化的function<T, int>。简单说,偏特化就是对某一个泛型参数的特例进行特殊处理。

还有一种特化,比如:

template<typename T, typename U>

inline T function<T, U*> (T a, U* b) {

  return a * (*b);

}

即是对U的类型特化。当我们调用function(double, int*)时,会调用function<T, U*>

看起来这样非常美好,但是如下的代码却不能正确通过连接。

template<typename T>

inline T function_err(T a) {

  return a * a;

}

 

template<>

inline int function_err<int> (int a) {

  return a * a;

}

看起来function_errfunction没有任何本质区别,都有一个关于int的偏特化。但是一旦该头文件被使用于多个目标文件时,连接这些目标文件就会出现特化函数的多重定义错误。

虽然我很明白这里的问题,由于function_err的特化已经没有任何泛型,它实际上就是一个普通函数,因而编译时编译器就不能正确处理该函数的泛型定义,导致了目标文件中的多重定义。如果把特化定义成简单函数就能通过连接。

template<typename T>

inline T function_ok(T a) {

  return a * a;

}

 

inline int function_ok(int a) {

  return a * a;

}

简单的看,这好像违背了偏特化的定义。实际上,这里的确没有偏特化,而是简单函数重载了泛型函数。由于重载有更明确地类型定义,因而会被首先使用,效果上等同于偏特化。重载有inline修饰,连接器就能正确本地连接。以上代码能正确编译连接。

综上所述,即使偏特化,也不能将所有的泛型参数都明确特化,而只能部分特化。如果明确特化,则需使用普通函数重载。另外,对于类和结构体的偏特化则不存在上述问题。(怎么看我都觉得是个编译器的bug

由于过于奇怪,特此记录。

 

 http://blog.csdn.net/xuminggang/article/details/4333214

函数模板为什么没有偏特化?问题解答

标签: function语言c

2009-07-09 09:51 2202人阅读 评论(2) 收藏 举报

版权声明:本文为博主原创文章,未经博主允许不得转载。

推荐Herb Sutter的文章:Why Not Specialize Function Templates? 

通过该文,明白了:

1. 没有函数偏特化,仅仅是因为C++标准语言说不行(you can't partially specialize them -- pretty much just because the language says you can't,另外我觉得有了函数重载,函数偏特化也没什么用

2. 函数的全特化并不参与函数重载, 因为担心全特化版本会弄乱函数重载解析(不是很明白)

3. 函数重载的解析次序依次是:

  • void f(int i); 这类plain old normal function
  • 某个没有进行全特化的template function
  • 如果这个没有进行全特化的template function有全特化版本,并且类型也比较匹配,则选择这个全特化版本

 

  评论这张
 
阅读(158)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017