C++模板之——函数模板详解及代码示例

简介: C++模板之——函数模板详解及代码示例

一、模板特点

  • 模板只是一个框架,不可以直接使用
  • 目的是为了提高代码复用性,将类型参数化

二、分类

C++提供两种模板机制:函数模板类模板。是一种泛型编程思想。

2.1 函数模板

语法:

// 作用:建立一个通用函数,其函数返回值类型和参数类型可以不具体指定,用一个虚拟的类型来表示。
template<typename T>
函数声明或者定义

说明:

template —— 表明要创建模板。

typename —— 表示一种数据类型,可以用 class 代替, T 就是具体的名称,通常为大写字母。

函数模板使用的注意事项

  • 自动类型推导,必须能推导出一致的数据类型
  • 模板使用前,必须要能确定出T的类型
2.1.1 代码示例

函数模板的两种调用方式:自动类型推导显式调用

#include <iostream>
using namespace std;
// 函数模板,提供一个通用的相加函数
template<typename T> // 声明一个模板
T add(T a, T b){ return a+b; }
// 普通函数,相同逻辑代码冗余
int add(int a, int b){ return a+b; }
double add(double a, double b){ return a+b; }
// 模板使用前,必须要能确定出T的类型
template<typename T>
void func(){ cout << "func called." << endl; }
int main(int argc, char* argv[])
{
  // 1. T自动类型推导
  cout << "==============自动类型推导================" << endl;  
    cout << "add(int, int): " << add(2, 3) << endl;
    cout << "add(double, double): " << add(2.1, 3.1) << endl;
  // 2. 显式的指定T类型
  cout << "==============显式指定类型==============" << endl;
    cout << "add(int, int): " << add<int>(2, 3) << endl;
    cout << "add(double, double): " << add<double>(2.1, 3.1) << endl;
    cout << "==============注意事项==============" << endl;
    // cout << "add(int, int): " << add(2, 3.1) << endl; // 错误,自动推导出的T类型不一致: add(int, double)
    // func(); // 错误,因为该函数没有使用T的地方,所以必须先指定T的类型
    func<int>();
  return 0;
}

运行结果:

2.1.2 函数模板与普通函数的区别

主要区别是:能否发生隐式类型转换

  • 普通函数可以发生隐式类型转换
  • 函数模板在使用自动类型推导时不能发生隐式类型转换,使用显式指定类型时可以,建议使用第二种
#include <iostream>
using namespace std;
// 函数模板
template<typename T>
T add(T a, T b){ return a+b; }
// 普通函数
int add(int a, int b){ return a+b; }
double add(double a, double b){ return a+b; }
int main(int argc, char* argv[])
{
    int a = 10;
    char c = 'c';
    cout  << "普通函数: " << add(a, c) << endl;
    // cout  << add(a, c) << endl; // 如果使用函数模板,编译器不知道将T该确定为 int 还是 char,编译报错
    cout  << "函数模板:" << add<int>(a, c) << endl;
  return 0;
}

运行结果:

2.2.3 函数模板和普通函数的调用规则
  1. 规则一:如果函数模板和普通函数都可以实现,有限调用普通函数
  2. 规则二:可以通过空模板参数列表来强制使用函数模板
  3. 规则三:函数模板也能发生重载
  4. 规则四:如何函数模板能发生更好的匹配,优先调用函数模板
#include <iostream>
using namespace std;
template<typename T>
void MyPrint(T a, T b) { cout  << "调用函数模板." << endl; }
template<typename T> // 函数模板重载
void MyPrint(T a, T b, T c) { cout  << "调用函数模板重载." << endl; }
void MyPrint(int a, int b) { cout  << "调用普通函数." << endl; }
int main(int argc, char* argv[])
{
    int a = 10, b = 20;
    MyPrint(a, b);  // 满足规则一:优先调用普通函数
    MyPrint<>(a, b); // 满足规则二:强制调用函数模板
    MyPrint(a, b, 100); // 满足规则三
    char A = 'A', B = 'B'; // 满足规则四:优先调用函数模板,因为普通函数还需要将char隐式的转为int,函数模板直接确定char
    MyPrint(A, B);
  return 0;
}

运行结果:

2.2.3 函数模板的局限性
template<class T>
void func(T a, T b){
    a = b;
}
template<class T>
void compare(T a, T b){
    if (a == b){
      //do something
    }
}

问题1:func函数模板提供的作用是将b的值赋给a。但是,如果T传的是一个数组,就无法实现。

问题2:compare函数模板提供的作用是比较a与b的值。但是,如果T传的是类,也无法比较。

为了解决这类问题,C++提供了可以为特定的类型提供具体化的模板。

#include <iostream>
#include <string>
using namespace std;
class Person{
public:
    Person(std::string name, int age){
        this->m_name = name;
        this->m_age = age;
    }
public:
    std::string m_name;
    int m_age;
};
template<class T>
bool MyCompare(T &a, T &b){
    return a == b ? true : false;
}
// 为Person类专门提供具体化的模板,会被优先调用
template<> bool MyCompare(Person& p1, Person& p2)
{
    if (p1.m_name == p2.m_name && p1.m_age == p2.m_age)
    {
        return true;
    }
    else
    {
        return false;
    }
}
int main(int argc, char* argv[])
{
    Person p1("panda", 20);
    Person p2("panda", 20);
    bool res = MyCompare(p1, p2);
    if (res) {
        std::cout << "p1 == p2" << std::endl;
    }
    else{
        std::cout << "p1 != p2" << std::endl;
    }
    return 0;
}

文章参考与<零声教育>的C/C++linux服务期高级架构系统教程学习:

相关文章
|
5月前
|
缓存 算法 程序员
C++STL底层原理:探秘标准模板库的内部机制
🌟蒋星熠Jaxonic带你深入STL底层:从容器内存管理到红黑树、哈希表,剖析迭代器、算法与分配器核心机制,揭秘C++标准库的高效设计哲学与性能优化实践。
C++STL底层原理:探秘标准模板库的内部机制
|
6月前
|
C++ Windows
应用程序无法正常启动(0xc0000005)?C++报错0xC0000005如何解决?使命召唤17频频出现闪退,错误代码0xC0000005(0x0)
简介: 本文介绍了Windows应用程序出现错误代码0xc0000005的解决方法,该错误多由C++运行库配置不一致或内存访问越界引起。提供包括统一运行库配置、调试排查及安装Visual C++运行库等解决方案,并附有修复工具下载链接。
1627 1
|
存储 安全 C语言
C++ String揭秘:写高效代码的关键
在C++编程中,字符串操作是不可避免的一部分。从简单的字符串拼接到复杂的文本处理,C++的string类为开发者提供了一种更高效、灵活且安全的方式来管理和操作字符串。本文将从基础操作入手,逐步揭开C++ string类的奥秘,帮助你深入理解其内部机制,并学会如何在实际开发中充分发挥其性能和优势。
|
8月前
|
API 数据安全/隐私保护 C++
永久修改机器码工具, exe一机一码破解工具,软件机器码一键修改工具【c++代码】
程序实现了完整的机器码修改功能,包含进程查找、内存扫描、模式匹配和修改操作。代码使用
|
9月前
|
存储 算法 安全
c++模板进阶操作——非类型模板参数、模板的特化以及模板的分离编译
在 C++ 中,仿函数(Functor)是指重载了函数调用运算符()的对象。仿函数可以像普通函数一样被调用,但它们实际上是对象,可以携带状态并具有更多功能。与普通函数相比,仿函数具有更强的灵活性和可扩展性。仿函数通常通过定义一个包含operator()的类来实现。public:// 重载函数调用运算符Add add;// 创建 Add 类的对象// 使用仿函数return 0;
279 0
|
9月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
229 0
|
9月前
|
C++
爱心代码 C++
这段C++代码使用EasyX图形库生成动态爱心图案。程序通过数学公式绘制爱心形状,并以帧动画形式呈现渐变效果。运行时需安装EasyX库,教程链接:http://【EasyX图形库的安装和使用】https://www.bilibili.com/video/BV1Xv4y1p7z1。代码中定义了屏幕尺寸、颜色数组等参数,利用随机数与数学函数生成动态点位,模拟爱心扩散与收缩动画,最终实现流畅的视觉效果。
1087 0
|
12月前
|
编译器 C++
模板(C++)
本内容主要讲解了C++中的函数模板与类模板。函数模板是一个与类型无关的函数家族,使用时根据实参类型生成特定版本,其定义可用`typename`或`class`作为关键字。函数模板实例化分为隐式和显式,前者由编译器推导类型,后者手动指定类型。同时,非模板函数优先于同名模板函数调用,且模板函数不支持自动类型转换。类模板则通过在类名后加`&lt;&gt;`指定类型实例化,生成具体类。最后,语录鼓励大家继续努力,技术不断进步!
|
12月前
|
安全 C++
【c++】继承(继承的定义格式、赋值兼容转换、多继承、派生类默认成员函数规则、继承与友元、继承与静态成员)
本文深入探讨了C++中的继承机制,作为面向对象编程(OOP)的核心特性之一。继承通过允许派生类扩展基类的属性和方法,极大促进了代码复用,增强了代码的可维护性和可扩展性。文章详细介绍了继承的基本概念、定义格式、继承方式(public、protected、private)、赋值兼容转换、作用域问题、默认成员函数规则、继承与友元、静态成员、多继承及菱形继承问题,并对比了继承与组合的优缺点。最后总结指出,虽然继承提高了代码灵活性和复用率,但也带来了耦合度高的问题,建议在“has-a”和“is-a”关系同时存在时优先使用组合。
723 6
|
安全 C++
【c++】模板详解(2)
本文深入探讨了C++模板的高级特性,包括非类型模板参数、模板特化和模板分离编译。通过具体代码示例,详细讲解了非类型参数的应用场景及其限制,函数模板和类模板的特化方式,以及分离编译时可能出现的链接错误及解决方案。最后总结了模板的优点如提高代码复用性和类型安全,以及缺点如增加编译时间和代码复杂度。通过本文的学习,读者可以进一步加深对C++模板的理解并灵活应用于实际编程中。
199 0