C++模版特化

问题:对于compare 函数模板,与 C 风格字符串一起使用,它们都不能正确工作:

// 函数模版定义
template <typename T>
int compare(const T &v1, const T &v2)
{
    if (v1 < v2) return -1;
    if (v2 < v1) return 1;
    return 0;
}

如果用两个 const char* 实参调用这个模板定义,函数将比较指针值:

cout << compare( "abc", "123" ); //使用char * 实参调用函数模版

它将告诉我们这两个指针在内存中的相对位置,但没有说明归法指针所指数组的。为了能够将 compare 函数用于字符串,必须提供一个知道怎样比较 C 风格字符串的特殊定义,这就是函数模版的特化(template specialization)版本。对用户而言,调用特化函数或使用特化类,与使用从通用模板实例化的版本无法区别。

模板特化定义:一个或多个模板形参的实际类型或实际值是指定的。特化的形式如下

  • 关键字 template 后面接一对空的尖括号 <>;
  • 再接模板名和一对尖括号,尖括号中指定这个特化定义的模板形参;
  • 函数形参表;
  • 函数体。

一、函数模板的特化

以compare函数为例,当模板形参类型绑定到 const char* 时:
//函数模版特化为 const char *
template <>
int compare<const char*>( const char* const &v1, const char* const &v2 )
{
    return strcmp(v1, v2);
}

注意:特化的声明必须与对应的模板相匹配

const char *cp1 = "world", *cp2 = "hi";
int i1, i2;
compare( cp1, cp2 ); // 调用特化版本
compare( i1, i2 ); // 调用普通模版

如果重载一个 const char *版本的compare函数时:

int compare(const char* const&, const char* const&);

调用compare函数时能够实现相同的功能,但是,重载函数与特化的函数模型区别在于

  • 重载函数时,对实参应用常规转换;
  • 当特化模板的时候,对实参类型不应用转换。


二、类模板的特化

类模版会出现与函数模版类似的问题。默认情况下,复制 C 风格字符串只会复制指针,不会复制字符。这种情况下复制指针将出现共享指针在其他环境中会出现的所有问题,最严重的是,如果指针指向动态内存,用户就有可能删除指针所指的数组。

// 类模版定义
template<T> class Compare {
public:
    static bool Equal( const T& lhs, const T& rhs )
        return lhs == rhs;
};
// 特化为 const char *
template<> class Compare<const char*> {
public:
    static bool Equal( const char* & lhs, const char* & rhs )
        return strcmp( lhs, rhs ) == 0;
};

注意:在特化整个类模版时,外部定义成员之前不能加 template<> 标记。

1.类模版部分特化

除了特化整个模版外,还可以只特化某些成员函数。这就与函数模版特化类似了。

// 只对Equal 函数进行特化
template<> class Compare<const char*> {
public:
    template <> static bool Equal<const char*> 
        return strcmp( lhs, rhs ) == 0;

    static Print( const T &lhs, const T &rhs ) //不进行特化
        cout << lhs << "==" << rhs << "? : ";
};

2.全特化与偏特化

如果一个模板有多个类型,那么只限定其中的一部分。

// 模版类定义
template <class T1, class T2>
class Test{
public:
    Test( T1 t1, T2 t2 ) : a(t1), b(t2) { cout << "模板类"; }
private:
    T1 a;
    T2 b;
};
//全特化
template <>
class Test<int, string>{
public:
    Test( int t1, string t2 ) : a(t1), b(t2) { cout << "全特化"; }
private:
    int a;
    string b;
};
//偏特化
template <class T2>
class Test<int>{
public:
    Test( int t1, T2 t2 ) : a(t1), b(t2) { cout << "偏特化"; }
private:
    int a;
    T2 b;
};


三、类模版特化的类型

1.特化为绝对类型

类模版特化为绝对类型,即直接为某个特定类型定义类模板。(二)中类模版的特化,特化为 const char* 类型,即是特化为绝对类型。如果特化为float 类型:

// 特化为 float 
template<>
class Compare<float>{
public:
    static bool Equal( const float& lhs, const float& rhs )
        return abs( lhs - rhs ) < 10e-3;
};
//可以这样使用float的特化模版:
float f1 = 10,
f2 = 10;
bool c = Compare<float>::Equal( f1, f2 );

2.特化为引用、指针类型

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

// 特化为 T*
template<class T>
class Compare<T*>{
public:
    static bool Equal( const T* lhs, const T* rhs )
        return Compare<T>::Equal( *lhs, *rhs );
};
// 可以这样使用特化为指针类型的模版:
int n1 = 10,
n2 = 10;
int *np1 = &n1,
*np2 = &n2;
bool c = Compare<int *>::Equal( np1, np2 );

3.特化为另一个类模版

对类型做某种限定,但又不绝对化。

// 特化为 vector<T>,T可以为 int,string 等
template <class T>
class Compare<vector<T> >{
public:
    static bool Equal( const vector<T> &lhs, const vector<T> &rhs )
    {
        if( lhs.size() != rhs.size() )return false;
        else
        {
            for( int i = 0; i != lhs.size(); ++i )
            if( lhs[i] != rhs[i] ) return false;
        }
        return true;
    }
};
//可以这样使用这个特化版本:
vector<int> v1;
for( int i = 0; i != 10; ++i )
v1.push_back(i);
vector<int> v2(v1);
bool res = Compare<vector<int> >::Equal( v1, v2 );
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值