文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C语言的模板与泛型编程你了解吗

2024-04-02 19:55

关注

模板与泛型编程浅谈

摘要(Effective C++):

​ C++template的最初发展动机很直接:让我们得以建立“类型安全”的容器如vector,list和map。然而当愈多人用上templates时,他们发现template有能力完成愈多可能的变化。容器当然很好,但泛型编程(generic programming)——写出的代码和其所处理的对象类型彼此独立——更好。STL算法如for_each,find和merge就是这一类编程的结果。最终人们发现,C++template机制自身是一部完整的图灵机:它可以用来计算任何可计算的值。于是导出了模板元编程(template mataprogramming),创造出“在C++编译器内执行并于编译完成时停止执行”的程序。

模板与泛型编程简单介绍

​ 面向对象编程(OOP)和泛型编程都可以处理编写程序时不知道类型的情况;二者的不同之处在于:OOP能处理类型在程序运行之前都未知的情况;而在泛型编程中,在编译时就能获知类型了

​ 我们所常用的STL标准库中,每一个容器都提供了单一的,泛型的定义,例如我们所常用的vector,我们可以定义很多类型的vector

vector<int> vi; // vi是装载int类型的vector容器的实例
vector<string> vs; // vs是装载string类型的vector容器的实例
vector<double> vd; // vd是装载double类型的vector容器的实例

模板是泛型编程的基础,一个模板就是一个创建类或者函数的蓝图或者公式

函数模板

// 简单的比较函数模板
template<typename T>
int cmp(const T& v1,const T& v2) {
    if(v1<v2)
        return -1;
    else if(v1>v2)
        return 1;
    else
        return 0;
}

函数定义以关键字template开始,后跟一个模板参数列表,这是一个逗号分隔的一个或多个模板参数的列表,用尖括号包围起来

**注:**在模板定义中,模板参数列表不能为空

模板参数列表表示在类或函数定义中用到的类型或者值。当我们使用模板的时候,我们可以(显式或隐式地)指定模板实参,将其绑定到模板参数上

简单了解模板的实例化过程

​ 众所周知,当你觉得模板编程十分智能的时候,一定是有东西在为你负重前行,C++提供了模板与泛型编程的这个能力,这便意味着有一个东西在为你动态地实现模板的功能,而这一定是比C++这个高级语言层面更为底层的东西,而我们所了解的知识中,比C++高级语言较为底层的东西,除了操作系统,便是编译器了。

​ 当我们调用一个函数模板的时候,编译器(通常)用函数实参来为我们推断模板实参。简单来讲,便是我们在调用函数模板的时候,编译器通过使用实参的类型来确定绑定到模板参数T的类型

cout<<cmp(1,0)<<endl; // T为int

在上诉代码中,函数cmp的实参类型是int,编译器便会推断出模板实参为int,并将它绑定到模板参数T上

简单来说,编译器用推断出的模板参数来为我们实例化一个特定版本的函数

模板编译

当编译器遇到一个模板定义的时候,它并不会生成代码。只有我们实例化出模板的一个特定的版本时,编译器才会生成其对应的代码。当我们使用(而不是定义)模板时,编译器才会生成代码。这个特性影响我们如何组织代码以及错误何时才可以被检测到

通常来说,我们将类定义和函数说明放在头文件中,而普通函数和类的成员函数的定义放在源文件中

模板则不尽相同:为了生成一个实例化的版本,编译器需要掌握函数模板或类模板成员函数的定义

总结与非模板代码不同,模板的头文件通常既包括声明也包括定义即函数模板和类模板成员函数的定义通常放在头文件中

大多数编译错误出现的时机 

**注意事项:**保证传递给模板的实参支持模板所要求的操作,以及这些操作在模板中能正确的工作,是调用者的责任

类模板

​ 类模板是用来生成类的蓝图的。与函数模板不同之处是,编译器不能为类模板推断模板参数类型。 所以我们必须在模板名后的尖括号中提供额外的信息——用来替代模板参数的模板实参列表

vector<int> vi;
deque<double> dd;
pair<string,int> key_val;

定义类模板

template<typename T>
class T_vector {
public:
	typedef T value_type;
    // 构造函数
    T_vector() =default;
    T_vectot(std::initializer_list<T> il);
    // 容器的元素数目
    size_type size() const { return data->size(); }
    bool empty() const { return data->empty(); }
    // 添加元素
    void push_back(const T& val) { 
        data->push_back(val);
    }
    void push_back(T &&val) {
        data->push_back(std::move(val));
    }
private:
    std::shared_ptr<std::vector<T> > data;
    // 若data[i]无效,则抛出msg
    void check(size_type i,const std::string &msg) const;
}

类似函数模板,类模板以关键字template开始,后跟模板参数列表。在类模板(及其成员)的定义中,我们将模板参数当作替身,代替使用模板时用户需要提供的类型或值

**注:**一个类模板的每一个实例都形成一个独立的类,而类模板的每个实例都有其自己版本的成员函数

​ 所以,我们可能会出现一个单一模板并不能满足所有类型的需求,而模板特例化就出现了

类模板成员函数的实例化

​ 默认的情况下,一个类模板的成员函数只有在程序用到它的时候才会实例化

// 实例化T_vector和接受initializer_list<int>的构造函数
T_vector<int> T_vi = { 0,1,2,3,4,5 };

如果一个成员函数没有被使用,则它将不会被实例化

为什么我们需要模板特例化?

当我们编写单一的模板时,使其对任何可能的模板实参都是最合适的,都能实例化,但者往往都是过于理想化的情况。在某些特殊的情况下,通用的模板的定义可能对特定的类型是不合适的,通用定义的模板可能会出现编译失败或者做得不够完善的情况。

​ 故,当我们不能(或者不希望)使用模板版本的时候,可以定义类或函数模板的一个特例化版本

定义函数模板特例化

// 原先cmp函数的特殊版本,用来处理特殊的字符数组的指针template<>int cmp(const char* const& p1,const char* const& p2) {    return strcmp(p1,p2);}// 原先cmp函数的特殊版本,用来处理特殊的字符数组的指针
template<>
int cmp(const char* const& p1,const char* const& p2) {
    return strcmp(p1,p2);
}

函数重载与模板特例化的区别

​ 当定义函数模板的特例化版本时,我们本质上接管了编译器的工作。即,我们为原先的模板的其中一个特殊的实例提供了定义。简而言之,特例化的本质是实例化一个模板,而非重载它,因此特例化并不影响函数匹配

注意事项:

类模板部分特例化

与函数模板不同的是,类模板的特例化不必为所有模板参数提供实参。一个类模板的部分特例化本身是一个模板,使用它时用户还必须为那些在特例化版本中指定的模板参数提供实参

我们只能部分特例化类模板,而不能部分特例化函数模板

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯