模板

在C语言中,想要实现多种类型的变量交换,需要用户定义需要实现交换的类型的函数。
用户自定义一个栈的数据结构,只能用于一种类型的使用,如果想要在一个程序中定义多种类型的栈,C语言是办不到的。那么在C++中就引入了模板。

函数模板

概率:实现这个模板是并没有给出具体的类型,而是在调用的时候,由编译器根据实参类型去生成该类型的函数。

使用格式

template <typename T1, typename T2, typename T3......>

返回值类型 函数名 (参数列表)

{}

//实现一个交换函数的模板

template <typename T>

void swap(T& p1, T& p2)

{

        T temp = p1;

        p1 = p2;

        p2 = temp; 

}

// typename 也可以使用class替换,但是不能使用strutct。

函数模板的实例化

概念:当不同类型参数使用函数模板时,称为函数模板实例化。实例化分为:隐式实例化和显式实例化。

//一个与函数模板同名的非函数模板函数可以共存。

int add(int a, int b) // 一个专门处理int类型的加法函数

{

        return a + b;

}

template <typename T>

T add(const T& a, const T& b)

{

        return a + b;
}

int main()

{

        int a1 = 1, a2 = 2;

        double b1 = 1.1, b2 = 2.2;

        add(a1, a2);

        add(b1, b2);

        // add(a1, b1) 这条语句会报错。编译器会根据a1和b1的类型去推导T的类型,可是这两个变量的类型不一样,所以编译不通过。有两种处理方式:1、强转;2、显式实例化。

        // 强转

        add(a1, (int)b1); // add((double)a1, b1);

        // 显式实例化

        add<int>(a1, b1);

        add(1, 2); // 调用专门处理int类型的加法函数。

        add<int>(1,2); // 调用编译器实例化出的函数

        // 当出现函数模板和非函数模板函数同名的情况,如果调用的类型满足非函数模板函数,那么就会优先调用该函数。

        return 0;

}

类模板

使用格式

template <class T1, class T2, ..., class Tn>

class 类模板名

{

// 类内成员定义

};

template <class T>

class Vector

{

public:

        Vector(int capacity = 10)

        :_a(new T[capacity]

        , _size(0)

        , _capacity(capacity) 

        {}

        ~Vector();

      void push_back(const T& x);

        T& operator [] (int pos)

        {

                assert(pos < _size);

                return _a[pos];

        }

private:

        T* _a;

        int _size;

        int _capacity;

}

// 当成员函数在类外定义时,需要加模板参数列表

template <class T>

// 指明所属

Vector<T>::~Vector()

{

        if(_a)

        {

                delete[] _a;

        }

        _size = _capacity = 0;

}

template <class T>

void Vector<T>::push_back(const T& x)

{

        _a[_size++] = x;

}

int main()

{

        // 注意:类模板不是真正的类,实例化出的才是真正的类。

        // 类模板的实例化

        Vector<int> v1;

        Vector<double> v2;

        return 0;

}

非类型模板参数 

模板参数分为:类型模板参数、非类型模板参数

类型模板参数:出现在模板参数列表中,class后typename之后。
非类型模板参数:使用一个常量作为类(函数)模板的一个参数,在类(函数)中可以将该参数当成一个常量使用。

namespace yair
{

     // 定义一个可以修改长度的数组
    template<class T, int N = 10>  // 给定一个缺省值
    class array
    {
    private:
        T _a[N];
    };
}


int main()
{
    yair::array<int> a0;  // a0的长度为10
    yair::array<int, 10> a1;   // a1的长度为10
    yair::array<int, 100> a2;  // a2的长度为100
    return 0;
}

注意:
1、浮点数、类对象是不可以作为非类型模板参数(这些可以作为非类型模板参数int、size_t、long、long long、char、short) 
2、非类型模板参数是一个常量

模板的特化

当我们想使用一个函数模板去比较两个变量的大小时,可以这样

namespace yair
{
    template<class T>
    bool IsEuqal(T a, T b)
    {
        return a == b;
    }

}

int main()
{
    int a = 0, b = 1;
    cout << yair::IsEuqal(a, b) << endl; // 可以比较,结果正确
    const char* p1 = "hello";
    const char* p2 = "world";
    cout << yair::IsEuqal(p1, p2) << endl; // 可以比较,但是结果是比较两个指针的地址,而不是内容

    return 0;
}

这个时候就无法比较p1和p2;此时就需要对模板进行特化。
模板特化:在原模板类的基础上,针对特殊类型所进行特殊化处理

模板特化分为:函数模板特化、类模板特化

函数模板特化

namespace yair
{
    template<class T>  // 必须要有一个基础模板
    bool IsEuqal(T a, T b)
    {
        return a == b;
    }
    template<>  // 关键字template后加尖括号
    bool IsEuqal<const char*>(const char* a, const char* b) // 函数名后跟尖括号,尖括号中必须指定需要特化的类型;函数的形参必须和模板函数的基础参数类型相同。
    {
        return strcmp(a, b) == 1;
    }
}

这样p1和p2就会调用这个特化的函数了。

注意:这样会优点麻烦,也可以直接实现一个字符串类型的比较函数。这样会更简单明了,可读性更高,所以函数模板不建议特化

 bool IsEuqal(const char*a, const char* b)
    {
        return return strcmp(a, b) == 1;
    }

类模板特化

全特化

namespace yair
{
    template<class T1, class T2>
    class Date
    {
    public:
        Date()
        {
            cout << "Date(T1, T2)" << endl;
        }
    private:
        T1 _a1;
        T2 _a2;
    };

    template<> 
    class Date<int, char>
    {
    public:
        Date()
        {
            cout << "Date(int, char)" << endl;
        }
    private:
        int _a1;
        char _a2;
    };
}
int main()
{
    yair::Date<int, int> d1;
    yair::Date<int, char> d2;
}

偏特化

对模板参数的一部分参数特化

namespace yair
{
    template<class T1, class T2>
    class Date
    {
    public:
        Date()
        {
            cout << "Date(T1, T2)" << endl;
        }
    private:
        T1 _a1;
        T2 _a2;
    };

    template<class T1>
    class Date<T1, char>
    {
    public:
        Date()
        {
            cout << "Date(T1, char)" << endl;
        }
    private:
        T1 _a1;
        char _a2;
    };

    template<typename T1, typename T2>  // 偏特化不仅是指特化部分参数,也是对模板参数进一步条件限制
    class Date<T1*, T2*>
    {
    public:
        Date() 
        { 
            cout << "Data<T1*, T2*>" << endl; 
        }

    private:
        T1 _a1;
        T2 _a2;
    };

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

    private:
        T1 _a1;
        T2 _a2;
    };
}
int main()
{
    yair::Date<int, int> d1;  // 调用基础模板
    yair::Date<double, char> d2; // 调用特化的int模板
    yair::Date<int*, int*> d3;  //调用特化的指针模板
    yair::Date<int&, int&> d4;  //调用特化的引用模板
}

模板分离编译

分离编译的概念:一个程序分为若干个源文件,每个源文件单独编译成一个目标文件,最后将这些目标文件链接在一起,形成一个单一的可执行文件的过程称为分离编译。

// a.h

template<class T>  // 声明

T Add(const T& left, const T& right);

// a.cpp

template<class T>   //定义

T Add(const T& left, const T& right)

{

        return left + right;

}

// main.cpp

#include"a.h"

int main()

{

         Add(1, 2);

         Add(1.0, 2.0);

        return 0;

}

在编译阶段,Add函数的定义没有实例化,(也就是说不知道它具体的类型)因此没有生成具体的函数。然后主函数中,在链接时,会去寻找函数的地址,但是这个Add函数没有生成具体代码,因此会链接错误。

解决方法:

1、将声明和定义放在一个文件中
2、在模板定义的地方显式实例化,但不实用

显式实例化模板的定义

// a.cpp

template<class T>   //定义

T Add(const T& left, const T& right)

{

        return left + right;

}

template    // 注意这里不需要加尖括号"<>"

int Add(const int& left, const int& right)    // 这里只能提供给int类型的加法函数,但是对于其他类型,必须一一实例化。所以说不实用。

{

        return left + right;

}

模板总结

优点:
1、模板的复用性很强,节省了代码,C++的标准模板库(STL)因此产生
2、增强了代码灵活性

缺点:
1、模板会导致代码膨胀(因为会有很多实例化)。也会导致编译时间变长
2、出现错误时,对错误不容易定位,维护性变差。

  • 24
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,我无法找到关于Django运费模板的具体信息。但是,我可以为您提供一些关于Django模板的基本知识。 Django模板是一种用于生成动态网页的工具。它允许您将静态HTML与动态数据结合在一起,以便在网页上显示动态内容。在Django中,您可以使用模板来呈现数据,并将其与视图函数中的逻辑进行分离。 在Django中,您可以创建一个模板文件,其中包含HTML和模板语言。模板语言允许您在模板中插入动态数据、循环和条件语句等。您可以使用模板标签和过滤器来处理数据并进行逻辑操作。 要使用Django模板,您需要在视图函数中加载模板,并将数据传递给模板进行渲染。然后,您可以将渲染后的模板发送给客户端以显示在浏览器中。 以下是一个简单的示例,演示如何在Django中使用模板: 1. 创建一个模板文件(例如template.html),其中包含HTML和模板语言: ```html <!DOCTYPE html> <html> <head> <title>My Django Template</title> </head> <body> <h1>Welcome to {{ website_name }}</h1> <p>Today's date is {{ current_date }}</p> </body> </html> ``` 2. 在视图函数中加载模板并将数据传递给模板进行渲染: ```python from django.shortcuts import render from datetime import date def my_view(request): website_name = "My Website" current_date = date.today() return render(request, 'template.html', {'website_name': website_name, 'current_date': current_date}) ``` 3. 在urls.py中配置URL与视图函数的映射关系: ```python from django.urls import path from .views import my_view urlpatterns = [ path('my-view/', my_view, name='my-view'), ] ``` 通过访问`http://localhost:8000/my-view/`,您将看到渲染后的模板页面,其中包含动态数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值