首页 > 编程语言 >泛型编程之模板

泛型编程之模板

时间:2024-03-27 22:45:17浏览次数:20  
标签:index 函数 编程 类型 参数 泛型 data 模板

1.函数模板

重要行:template<typename T, typename T1>

关键值class和typename含义相同,那么我们以后就使用typename即可。

 

一般情况下的格式:

template<模板参数列表>

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

 

模板参数列表的理解:

  函数参数列表在运行时调用者用实参来初始化形参

  而对于模板参数列表,编译器用实际的不同版本的模板实参,代替,对应的模板参数,来实例化不同版本的模板。

两种模板参数:

  模板类型参数:(书上这样命名很奇怪,他对应的有非类型模板参数,所以我还是喜欢称呼他为类型模板参数),可以用来指定返回类型,函数参数类型,以及在函数体内使用。

  非类型模板参数: 模板实参必须是常量表达式,编译器使用字面常量来代替他们。

注:

模板在被使用的时候编译器才会生成代码,即“实例化”后。所以模板的头文件一般同时包括模板的声明和定义。模板要被实例化,那么他的一切都应当是可见的,所有模板作用域内名字都应该找到他的声明。

如果模板函数内部部分实现不支持推导的类型,我们在实例化模板的时候才会报错,所以编译和链接阶段都可能报错,因为处于不同编译单元的函数可能在链接阶段才被真正使用,在编译阶段我们可以只看到声明。(不重要,反正都是报错0.0)

模板函数的函数参数不强制需要使用模板参数

// AI生成
#include <iostream> // 定义一个函数模板,接受一个类型参数 T 和一个整数参数 N // 含有非类型模板参数,使用的时候需要尖括号指定 template <typename T, int N> void printNTimes(const T& value) { for (int i = 0; i < N; ++i) { std::cout << value << " "; } std::cout << std::endl; } int main() { // 使用函数模板,类型参数为 int,非类型参数为 5 printNTimes<int, 5>(42); // 输出 "42 42 42 42 42 " // 使用函数模板,类型参数为 double,非类型参数为 3 printNTimes<double, 3>(3.14); // 输出 "3.14 3.14 3.14 " return 0; }
// AI生成
#include <iostream>

template <typename T>
void printNTimes(const T& value, int N) {
    for (int i = 0; i < N; ++i) {
        std::cout << value << " ";
    }
    std::cout << std::endl;
}

int main() {
    // 调用函数模板,不需要尖括号
    printNTimes(42, 5); // 输出 "42 42 42 42 42 "

    // 调用函数模板,不需要尖括号
    printNTimes(3.14, 3); // 输出 "3.14 3.14 3.14 "

    return 0;
}

 

2.类模板

与函数模板不同的是,编译器不能为类模板推断模板参数类型,需要我们利用尖括号提供额外信息(ps:毕竟类不像函数在调用的时候有实参列表),这些额外信息称之为显式模板实参。

 

类模板成员函数的实例化

类模板的成员函数只在使用时才被实例化(包括static成员函数),这意味着只有在实际调用该成员函数时,编译器才会生成相应的代码。这种延迟实例化的机制有助于减少编译时间和代码大小。

而且这一特性使得即使某种类型不能完全符合模板操作要求,我们依然可以使用该类型实例化类,只不过我们不去使用他的“非法”成员。

// AI
#include <iostream>

template <typename T>
class MyClass {
public:
    void printValue(T value) {
        std::cout << "Value: " << value << std::endl;
    }
};

int main() {
    MyClass<int> intInstance;
    intInstance.printValue(5); // 实例化 printValue<int>(int)

    MyClass<double> doubleInstance;
    doubleInstance.printValue(3.14); // 实例化 printValue<double>(double)

    return 0;
}

 

注:在类模板的作用域内,我们可以直接类模板的类名字(官方称谓:模板名),比如,某些成员的返回值 MyClass getData() { return *this; } 不用写成MyClass<T>。

但是要注意的是类外成员定义中函数返回值类型不在类作用域中,函数体内部在类作用域中。 

 

模板类型别名

  单个模板实例的别名:typedef Blob<string> A;

  类模板的别名: template<typename T> using test = std::pair<T, int>; 使用的时候 test<string>;

 

 

// 利用AI生成
#include <iostream>
#include <vector>

template <typename T>
class Container {
private:
    std::vector<T> data; // 内部使用 vector 模板存储元素,使用了模板参数T

public:
    // 在类内部声明成员函数
    void add(const T& value) {
        data.push_back(value);
    }
    void remove(int index) {
        if (index >= 0 && index < data.size()) {
            data.erase(data.begin() + index);
        }
    }
    void update(int index, const T& value) {
        if (index >= 0 && index < data.size()) {
            data[index] = value;
        }
    }
    T& get(int index) {
        return data[index];
    }
    int getSize() const {
        return data.size();
    }

    // 在类外部定义的成员函数,使用了类模板的类型参数 T
    void print();
};

// 在类外部定义的成员函数,使用了类模板的类型参数 T
template <typename T>
void Container<T>::print() {
    for (const auto& item : data) {
        std::cout << item << " ";
    }
    std::cout << std::endl;
}

int main() {
    // 使用 int 类型的类模板
    Container<int> intContainer;
    intContainer.add(1);
    intContainer.add(2);
    intContainer.add(3);
    std::cout << "Size: " << intContainer.getSize() << std::endl; // 输出 "Size: 3"
    intContainer.print(); // 输出 "1 2 3"

    // 使用 double 类型的类模板
    Container<double> doubleContainer;
    doubleContainer.add(3.14);
    doubleContainer.add(2.718);
    std::cout << "Size: " << doubleContainer.getSize() << std::endl; // 输出 "Size: 2"
    doubleContainer.print(); // 输出 "3.14 2.718"

    return 0;
}

 

标签:index,函数,编程,类型,参数,泛型,data,模板
From: https://www.cnblogs.com/W-cats/p/18100491

相关文章

  • 小猴编程周赛C++ | 最小能力差
    学习C++从娃娃抓起!记录下在学而思小猴编程学习过程中的题目,记录每一个瞬间。侵权即删,谢谢支持!附上汇总贴:小猴编程C++|汇总-CSDN博客【题目描述】某校信竞社团有nnn......
  • 小猴编程周赛C++ | 卡牌顺序
    学习C++从娃娃抓起!记录下在学而思小猴编程学习过程中的题目,记录每一个瞬间。侵权即删,谢谢支持!附上汇总贴:小猴编程C++|汇总-CSDN博客【题目描述】小猴有nnn卡牌,编号......
  • 网络编程之流式套接字
    流式套接字(SOCK_STREAM)是一种网络编程接口,它提供了一种面向连接的、可靠的、无差错和无重复的数据传输服务。这种服务保证了数据按照发送的顺序被接收,使得数据传输具有高度的稳定性和正确性。通常用于那些对数据的顺序和完整性有严格要求的应用。通常由传输控制协议(TCP)来实现。......
  • 13DOM编程API(一)
    1<!DOCTYPEhtml>2<htmllang="en">3<head>4<metacharset="UTF-8">5<metaname="viewport"content="width=device-width,initial-scale=1.0">6<title>Do......
  • 15DOM编程API(三)
    1<!DOCTYPEhtml>2<htmllang="en">3<head>4<metacharset="UTF-8">5<metaname="viewport"content="width=device-width,initial-scale=1.0">6<title>Document......
  • 14DOM编程API(二)
    1<!DOCTYPEhtml>2<htmllang="en">3<head>4<metacharset="UTF-8">5<metaname="viewport"content="width=device-width,initial-scale=1.0">6<title>Document......
  • 消息sms 邮箱/手机号/push发送的方案 & 定时任务xxlJob灵活度 & 泛型和发送的模板类设
    消息sms邮箱/手机号/push发送的方案&定时任务xxlJob灵活度&泛型和发送的模板类设计1.消息sms邮箱/手机号/push发送的方案1.判断收件人地址是否为空,不为空则发送邮件。为空则不发送。可以通过该方法终止一些消息的发送。2.收件人的地址可以配置在Apollo中,直接删除该key......
  • Python篇之网络编程,实现简单的服务端和客户端的内容传输
    本小节内容:实现简单的信息交流文章目录一、Socket介绍二、客户端与服务端三、在python中实现网络通信1.服务端2.客户端3.连接测试一、Socket介绍socket(简称套接字)模块是其内置的标准库之一,它实现了BSDsocketsAPI,允许开发者在Python程序中进行网络通......
  • 语法回顾-《Verilog编程艺术》之数据类型
    目录线网(net)变量(variable)线网和变量的区别向量数组参考《Verilog编程艺术》魏家明著线网(net)用于表示结构体(如逻辑门)之间的连接。除了trireg之外,所有其他的线网类型都不能保存值,线网的值是由driver决定的。例如由连续赋值驱动或由逻辑门驱动。如果driver没有驱动线......
  • 语法回顾-《Verilog编程艺术》之Verilog特性
    目录Verilog标准:抽象级别:行为级模型:RTL级模型:门级模型:可综合子集:参考《Verilog编程艺术》魏家明著Verilog标准:Verilog一共发行了三个标准:Verilog-1995、Verilog-2001和Verilog-2005.抽象级别:Verilog可以在三种抽象级上进行描述:行为级模型,RTL级模型和门级模型。......