【C++初阶11-模版进阶】解锁C++模版更多玩法

本文介绍了C++中的模板高级特性,包括非类型模板参数的使用,如用整型参数来定制类模板的行为;模板的特化,用于处理模板无法覆盖的特殊情况,包括函数模板和类模板的全特化及偏特化;以及模板的分离编译问题,强调了模板不能分离编译的原因及解决方法,需要在调用处显式实例化成员函数。
摘要由CSDN通过智能技术生成

今天,带来模版进阶的讲解。
主要讲解:

  • 非类型模版参数
  • 模版的特化
  • 模版的分离编译

文中不足错漏之处望请斧正!


非类型模版参数

模版参数分为类型模版参数和非类型模版参数。

可以这么理解:前者是为了泛化类型,后者给定了实际类型,更像是给类模板所有实例用的一个常量

也有这样的要求:浮点数、类对象以及字符串是不允许作为非类型模板参数的。基本上就是用整形家族来当非类型模版参数。

声明格式

template <整形 参数名 =>
class vector
{};

见见猪跑

template <class T, size_t N = 10>
class vector
{
public:
private:
    T _arr[N]; //大小是静态的数组
};

模版的特化

模版的特化就是模板的特殊实例。

为什么

模板再神通广大也并不能用在所有场景吧?总有那么几个特殊场景。

我们只能像以前那样单独写了吗?单独写可以,但也能用模版的特化解决

怎么玩

函数模版的特化

template<class T>
返回值类型 函数模版名(参数列表)

template<>
返回值类型 特化的函数名<要特化的类型>(参数列表)

见见猪跑

struct test {
    int _i = 1;
};

template<class T>
int toInt(T input) {
    cout << "int toInt(T input)" << endl;
    return (int) input;
}

template<>
int toInt<test>(test input) {
    cout << "int toInt<test>(test input)" << endl;
    return input._i;
}

int main() {
    test t;
    char ch = 'a';

    toInt(t);
    toInt(ch);
    return 0;
}
int toInt<test>(test input)
int toInt(T input)

注意:特化出的实例参数列表必须和模板完全相同。

不过,为了简单方便,遇到函数模版的特殊场景会直接单独提供,这样简单清晰。

类模板的特化

全特化

template<class T1, class T2>
class test {
public:
    test() {
        cout << "template<class T1, class T2> class test " << endl;
    }

    T1 _t1;
    T2 _t2;
};

template<>
class test<int, double> {
public:
    test() {
        cout << "template<> class test<int, double>" << endl;
    }

    int _t1;
    double _t2;
};

int main() {
    test<char, int> t1;
    test<int, double> t2;

    return 0;
}
template<class T1, class T2> class test 
template<> class test<int, double>

半特化(偏特化)

目的1:将参数特化
template<class T1, class T2>
class test {
public:
    test() {
        cout << "template<class T1, class T2> class test " << endl;
    }

    T1 _t1;
    T2 _t2;
};

template<class T1>
class test<T1, int> {
public:
    test() {
        cout << "template<class T1> class test<T1, int>" << endl;
    }

    T1 _t1;
    int _t2;
};

int main() {
    test<char, char> t1;
    test<char, int> t2; //第二个模版参数传了int,就走了特化

    return 0;
}
template<class T1, class T2> class test 
template<class T1> class test<T1, int>
目的2:对参数进一步限制
template<class T1, class T2>
class test {
public:
    test() {
        cout << "template<class T1, class T2> class test " << endl;
    }

    T1 _t1;
    T2 _t2;
};

template<class T1, class T2>
class test<T1 *, T2 *> {
public:
    test() {
        cout << "template<class T1, class T2> class test<T1*, T2*>" << endl;
    }
};

template<class T1, class T2> class test 
template<class T1, class T2> class test<T1*, T2*>

模版的分离编译

核心结论

模版不可以分离编译。

为什么

假如我们分离成这样:

  • add.h
  • main.cpp

add.h中有类模版,main.cpp中用类模板实例出类型,再用类型实例出对象,调用对象的成员函数。

  1. 对象的成员函数对main来说是外部符号,等后续链接
  2. 类模板的成员函数是在调用的时候才实例

即,模板处不知道有人调用就没实例成员函数 && 调用处默认认为外部符号都能直接链接使用 = 链接一个根本没实例出来的函数 = 链接错误

解决办法

  1. 声明定义不分离
  2. 调用处显式实例化类模板的成员函数
//  stack.cpp
#include "stack.h"
template<class T>
void Stack<T>::push(const T& data)
{
    _a[_size++] = data;
}

template<class T>
void Stack<T>::print()
{
    for(int i = 0; i<_size; i++)
    {
        cout << _a[i] << ' ';
    } cout << endl;
}

template class Stack<int>;//在最下面实例化才能实例化到全部模版(顺序编译)

:1

今天的分享就到这里了,感谢您能看到这里。

这里是培根的blog,期待与你共同进步!

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周杰偷奶茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值