您现在的位置是:首页 >其他 >【C++初阶11-模版进阶】解锁C++模版更多玩法网站首页其他

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

周杰偷奶茶 2024-06-11 00:00:02
简介【C++初阶11-模版进阶】解锁C++模版更多玩法

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

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

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


非类型模版参数

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

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

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

声明格式

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,期待与你共同进步!

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。