王建设医生个人网站,智能网站搭建,营销型网站的公司,太原网站制作报价最近在复习C有关知识#xff0c;又重新看Effective C#xff0c;收获颇丰。原来以前看这边书#xff0c;好多地方都是浅尝辄止。Effective C条款25#xff1a;考虑写出一个不抛出异常的swap函数#xff0c;涉及到C模板专门化(Templates S… 最近在复习C有关知识又重新看Effective C收获颇丰。原来以前看这边书好多地方都是浅尝辄止。Effective C条款25考虑写出一个不抛出异常的swap函数涉及到C模板专门化(Templates Specialization)和函数重载(overloading)问题而当重载与模板搅合在一起时许多问题都变得“模棱两可”。 首先回顾Effective C条款25考虑写出一个不抛出异常的swap函数想告诉我们什么东西。 swap函数为我们提供了异常安全编程的方法以及用来作为处理自我赋值一种常见机制因此实现一个不抛出异常的swap函数变得相对重要起来。缺省情况下的swap函数的典型实现如下 namespace std
{templatetypename Tvoid swap(T a, T b){T temp(a);a b;b temp; }
} 然后对于模型数据类型其成员变量是指针指向一个对象保存了数据(pointer to implementation手法)。如果copying函数采用了deep copying方法上面的代码将会非常低效因为只需要互换a与b指针即可。问题是缺省版本swap对类型无法可知这些信息因此针对上述情况需要专门化swap函数。 1如果T是class可以先让T提供一个swap函数完成swap功能然后借由functhon template的全特化实现专门化的swap函数 class Widge
{
public:void swap(Wiget other){using std::swap();swap(pImpl, other.pImpl);}private: WidetImpl* pImpl;};//为程序提供一个特化版本的swap: namespace std { template void swapWidegt(Widget a, Widget b) { a.swap(b); } } 上面的代码很好的与STL容器保持了一致性因为STL容器也都提供了swap成员函数和std::swap特化版本。 2如果Widget与WidgetImpl不是class而是class template特化版本的swap函数我们可能想写成这样的形式 namespace std
{templateclass Tvoid swapWidegtT(WidgetT a, WidgetT b) {a.swap(b);}
} 然而这个代码却无法通过编译C不支持function template的偏特化我们需要使用模板函数的重载技术 namespace std
{templateclass Tvoid swap( WidgetT a, WidgetT b) //重载了function templates{a.swap(b);}
} 问题似乎已经解决了嗯是的还存在一个问题用户可以全特化std内的templates但是不能新的对象(template、function、class)。解决方法是将这些类与swap函数放到新的命名空间中这边便独立与std命名空间。 --------------------------------------------------------------------华丽分割线-------------------------------------------------------------------- 上面介绍的内容涉及到以下的内容1模板函数2重载函数3全特化和偏特化。当这些东西交织在一起的时候我们需要足够的耐心做区分甄别。 1模板类、模板函数与重载 // Example 1: Class vs. function template, and overloading //// A class templatetemplatetypename T class X { /*...*/ }; // (a) 类模板// A function template with two overloadstemplatetypename T void f( T ); // (b) 函数模板 templatetypename T void f( int, T, double ); // (c) 函数模板重载 (a)、(b)、(c)均没有专门化这些未被专门化的template又被称为基础基模板。 2特化 template class可以有全特化与偏特化两种 template function仅能全特化。 // Example 1, continued: Specializing templates
//
// A partial specialization of (a) for pointer types
templatetypename T class XT* { /*...*/ }; // A full specialization of (a) for int
template class Xint { /*...*/ };// A separate base template that overloads (b) and (c)
// -- NOT a partial specialization of (b), because
// theres no such thing as a partial specialization
// of a function template!
templateclass T void f( T* ); // (d)// A full specialization of (b) for int
template void fint( int ); // (e)// A plain old function that happens to overload with
// (b), (c), and (d) -- but not (e), which well
// discuss in a moment
void f( double ); // (f) 当function template与重载搅合在一起的时候就存在匹配哪个版本函数的问题匹配规则如下 1首先查找non template function 如果在这些函数中匹配成功则匹配结束(first-class citizens) 2否定在base template function 中查找最匹配的函数并实例化如果base template function恰巧有提供全特化版本模板函数则使用全特化版本(sencond-class citizens) 将以上两个规则运用的例子 // Example 1, continued: Overload resolution
//
bool b;
int i;
double d;f( b ); // calls (b) with T bool
f( i, 42, d ); // calls (c) with T int
f( i ); // calls (d) with T int
f( i ); // calls (e)
f( d ); // calls (f) 最后一个问题如何判断哪个base template function被specialization再看下面的例子: // Example 2: Explicit specialization
//
templateclass T // (a) a base template
void f( T );templateclass T // (b) a second base template, overloads (a)
void f( T* ); // (function templates cant be partially // specialized; they overload instead)template // (c) explicit specialization of (b)
void f(int*);// ...int *p;
f( p ); // calls (c) c是b是全特化f(p)将会调用符合人们的一般想法但是如果置换b与c的顺序结果就不那么一样了 // Example 3: The Dimov/Abrahams Example
//
templateclass T // (a) same old base template as before
void f( T );template // (c) explicit specialization, this time of (a)
void f(int*);templateclass T // (b) a second base template, overloads (a)
void f( T* );// ...int *p;
f( p ); // calls (b)! overload resolution ignores // specializations and operates on the base // function templates only 这个时候c将是a的全特化(编译器没看到后面的b的定义)。按照配对规则首先查找base template function最适合匹配的b正好最为匹配并且没有全特化版本因此将会调用b。 重要准则 1如果我们希望客户化base template function直接利用传统的函数形式如果使用重载形式那么请不要提供全特化版本。 2如果正在编写一个base template function不要提供特化和重载版本将客户化定制功能下放给用户。实现方法是在class template 同static 函数接口 // Example 4: Illustrating Moral #2
//
templateclass T
struct FImpl;templateclass T
void f( T t ) { FImplT::f( t ); } // users, dont touch this!templateclass T
struct FImpl
{ static void f( T t ); // users, go ahead and specialize this
}; 准则2的动机就是利用class template 特化与偏特化功能实现function 特化与偏特化功能。 参考文献 Effective C, Scott Meyers Why Not Specialize Function Templates?, C/C Users Journal, 19(7), July 2001 转载于:https://www.cnblogs.com/wangbogong/p/3249238.html