当前位置: 首页 > news >正文

《C++探幽:模板从初阶到进阶》

文章目录

    • :red_circle:一、模板基础:开启泛型编程之门
      • (一)泛型编程的必要性
      • (二)函数模板
        • 1. 函数模板概念
        • 2. 函数模板定义格式
        • 3. 函数模板原理
        • 4. 函数模板实例化
        • 5. 模板参数匹配原则
      • (三)类模板
        • 1. 类模板定义格式
        • 2. 类模板实例化
    • :red_circle:二、模板进阶:拓展代码灵活性
      • (一)非类型模板参数
        • 1. 概念
        • 2. 注意事项
      • (二)模板特化
        • 1. 概念
        • 2. 函数模板特化
          • (1)特化步骤
          • (2)示例
          • (3)注意事项
        • 3. 类模板特化
          • (1)全特化
          • (2)偏特化
            • ① 部分特化
            • ② 参数进一步限制的特化
          • (3)类模板特化应用示例
        • 4. 模板特化的总结
      • (三)模板分离编译
        • 1. 分离编译概念
        • 2. 模板分离编译问题
        • 3. 解决方法
    • :red_circle:三、模板总结:权衡利弊,合理运用
      • (一)模板的优点
      • (二)模板的缺陷
    • :red_circle:四、模板应用案例深度剖析
      • (一)STL 与模板的紧密联系
      • (二)自定义泛型算法
    • :red_circle:五、模板与面向对象编程的融合
      • (一)模板类与继承、多态的结合
      • (二)模板方法模式的模板实现
    • :red_circle:六、模板的高级特性探索
      • (一)模板元编程( TMP )
      • (二)可变参数模板
    • :red_circle:七、模板在实际项目中的最佳实践
      • (一)合理使用模板提升代码质量
      • (二)避免模板滥用
      • (三)优化模板代码的策略
    • :red_circle:八、模板的未来发展与挑战
      • (一)C++ 新标准对模板的演进
      • (二)模板面临的挑战与应对策略
    • :red_circle:九、模板与其他编程语言泛型机制的对比
      • (一)与 Java 泛型对比
      • (二)与 C# 泛型对比
    • :red_circle:十、总结与展望


[作者的个人Gitee>🌟](友人A (friend-a188881041351) - Gitee.com)🌟

每日一言:“**🌸🌸存在是一场无尽的对话,我们既是提问者,也是答案。🔅🔅”

在 C++ 编程语言中,模板是一种强大的工具,它允许程序员编写与类型无关的通用代码,从而实现代码复用和增强代码灵活性。本文将深入解析 C++ 模板的基础知识、进阶技巧以及实际应用场景,帮助读者全面掌握模板的核心概念与实践方法。

🔴一、模板基础:开启泛型编程之门

(一)泛型编程的必要性

在传统编程中,若要实现一个交换函数,我们可能会针对不同数据类型编写多个重载函数:

void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}
void Swap(double& left, double& right)
{double temp = left;left = right;right = temp;
}
void Swap(char& left, char& right)
{char temp = left;left = right;right = temp;
}

这种做法存在明显弊端:代码复用率低,每新增一种类型就需要手动添加对应函数;代码可维护性差,一处出错可能导致所有重载函数受影响。

模板的出现解决了这一难题。模板允许我们定义一个通用的“模具”,编译器可根据不同类型参数生成对应代码。这种编写与类型无关的通用代码方式,就是泛型编程。

(二)函数模板

1. 函数模板概念

函数模板是一个函数家族的蓝图,它定义了函数的通用形式,可在使用时被参数化,根据实参类型生成特定类型版本的函数。

2. 函数模板定义格式
template<typename T1, typename T2, ..., typename Tn>
返回值类型 函数名(参数列表)
{// 函数体
}

其中,typename 用于定义模板参数关键字,也可使用 class 关键字替代,但不能使用 struct

示例 - 通用交换函数:

template<typename T>
void Swap(T& left, T& right)
{T temp = left;left = right;right = temp;
}
3. 函数模板原理

函数模板本身并非具体函数,而是一个生成函数的模具。编译器在编译阶段根据传入实参类型推演模板参数实际类型,并生成对应代码。例如,当使用 double 类型调用 Swap 函数模板时,编译器会生成专门处理 double 类型的代码。

4. 函数模板实例化

函数模板实例化分为隐式实例化和显式实例化:

  • 隐式实例化:编译器根据实参类型自动推演模板参数类型。示例:
    template<class T>
    T Add(const T& left, const T& right)
    {return left + right;
    }
    int main()
    {int a1 = 10, a2 = 20;double d1 = 10.0, d2 = 20.0;Add(a1, a2); // 隐式实例化为处理 int 类型的 Add 函数Add(d1, d2); // 隐式实例化为处理 double 类型的 Add 函数return 0;
    }
    
  • 显式实例化:在函数名后的 < > 中指定模板参数实际类型。示例:
    int main(void)
    {int a = 10;double b = 20.0;Add<int>(a, b); // 显式指定模板参数类型为 intreturn 0;
    }
    
5. 模板参数匹配原则
  • 非模板函数与同名函数模板可共存。若其他条件相同,调用时优先选择非模板函数;若模板可生成更匹配函数,则选择模板。
  • 模板函数不允许自动类型转换,而普通函数可以进行自动类型转换。

(三)类模板

1. 类模板定义格式
template<class T1, class T2, ..., class Tn>
class 类模板名
{// 类内成员定义
};

示例 - 栈的实现:

#include <iostream>
using namespace std;
template<typename T>
class Stack
{
public:Stack(size_t capacity = 4){_array = new T[capacity];_capacity = capacity;_size = 0;}void Push(const T& data);
private:T* _array;size_t _capacity;size_t _size;
};
template<class T>
void Stack<T>::Push(const T& data)
{// 扩容逻辑(此处省略)_array[_size] = data;++_size;
}
2. 类模板实例化

类模板实例化需在类模板名后跟 < >,将实例化类型放在 < > 中。类模板名本身并非真正的类,实例化后的结果才是具体类。示例:

int main()
{Stack<int> st1;    // 实例化为处理 int 类型的栈Stack<double> st2; // 实例化为处理 double 类型的栈return 0;
}

🔴二、模板进阶:拓展代码灵活性

(一)非类型模板参数

1. 概念

非类型模板参数是用常量作为类(函数)模板参数,在模板中可将该参数当作常量使用。

2. 注意事项
  • 浮点数、类对象及字符串不能作为非类型模板参数。
  • 非类型模板参数必须在编译期能确定结果。

(二)模板特化

1. 概念

模板特化用于处理特殊类型,当通用模板在某些特殊类型上无法正常工作或结果错误时,可通过特化为特定类型提供专门实现。

2. 函数模板特化
(1)特化步骤
  1. 先有基础函数模板。
  2. template 后接空尖括号 <>
  3. 函数名后跟尖括号,指定特化类型。
  4. 函数形参表必须与基础模板参数类型完全相同。
(2)示例

通用比较函数模板:

template<class T>
bool Less(T left, T right)
{return left < right;
}

对指针类型特化:

template<>
bool Less<Date*>(Date* left, Date* right)
{return *left < *right;
}
(3)注意事项

函数模板特化虽可行,但一般不推荐,因特化版本过多会使代码难以维护。对于复杂类型,直接编写非模板函数可能更优。

3. 类模板特化
(1)全特化

全特化是确定模板参数列表中所有参数。示例:

template<class T1, class T2>
class Data
{
public:Data() { cout << "Data<T1, T2>" << endl; }
private:T1 _d1;T2 _d2;
};
template<>
class Data<int, char>
{
public:Data() { cout << "Data<int, char>" << endl; }
private:int _d1;char _d2;
};
(2)偏特化
① 部分特化

部分特化是特化模板参数列表中的部分参数。示例:

template<class T1, class T2>
class Data
{
public:Data() { cout << "Data<T1, T2>" << endl; }
private:T1 _d1;T2 _d2;
};
template <class T1>
class Data<T1, int>
{
public:Data() { cout << "Data<T1, int>" << endl; }
private:T1 _d1;int _d2;
};
② 参数进一步限制的特化

示例:

template <typename T1, typename T2>
class Data<T1*, T2*>
{
public:Data() { cout << "Data<T1*, T2*>" << endl; }
private:T1* _d1;T2* _d2;
};
(3)类模板特化应用示例

对排序中指针比较问题的解决:

#include <vector>
#include <algorithm>
template<class T>
struct Less
{bool operator()(const T& x, const T& y) const{return x < y;}
};
// 特化指针类型
template<>
struct Less<Date*>
{bool operator()(Date* x, Date* y) const{return *x < *y;}
};
int main()
{// 对 Date 对象排序vector<Date> v1;// ... 添加元素并排序sort(v1.begin(), v1.end(), Less<Date>());// 对 Date 指针排序vector<Date*> v2;// ... 添加元素并排序sort(v2.begin(), v2.end(), Less<Date*>());return 0;
}
4. 模板特化的总结

模板特化提供了针对特殊情况的灵活处理方式,但过度使用可能导致代码复杂度增加。在实际开发中,应权衡通用模板与特化模板的使用,以保持代码的可读性和可维护性。

(三)模板分离编译

1. 分离编译概念

分离编译是将程序分为多个源文件,单独编译每个文件生成目标文件,最后链接成可执行文件的过程。

2. 模板分离编译问题

当模板声明与定义分离时,可能出现链接错误。例如:

// 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;
}

上述代码会导致链接错误,因模板函数定义在 a.cpp 中,而 main.cpp 中调用时编译器无法在该编译单元内找到定义。

3. 解决方法
  • 推荐方法:将模板的声明和定义放在同一文件(通常是头文件)中。这样可确保在使用模板时,编译器能同时看到声明和定义,避免链接问题。
  • 显式实例化:在模板定义的源文件中显式指定实例化类型,但此方法不够实用,不推荐广泛使用。

🔴三、模板总结:权衡利弊,合理运用

(一)模板的优点

优点分类详细说明
代码复用模板允许编写通用代码,避免为不同类型重复编写相似逻辑,显著提高代码复用率,减少开发工作量。例如,STL(标准模板库)利用模板提供了通用的容器、算法等组件,适用于多种数据类型。
灵活性增强模板能适应多种数据类型,程序员可编写更灵活的函数和类。如一个通用排序函数可对不同类型元素进行排序,无需关心具体类型,只需类型支持相应操作。
性能优势相较于运行时多态(如虚函数),模板在编译时就确定了具体类型,无运行时开销,能生成更高效的代码。编译器可针对特定类型优化代码,提升程序运行效率。

(二)模板的缺陷

缺陷分类详细说明
代码膨胀每次实例化模板时,编译器会生成一份对应类型的代码。若模板在多个文件中被实例化,或模板本身庞大复杂,可能导致代码体积大幅膨胀,增加可执行文件大小和内存占用。
编译时间增加模板的复杂性和多次实例化会使编译过程变长。编译器需处理模板定义、根据实参推演类型、生成实例化代码等步骤,尤其在大型项目中,模板的过度使用可能显著延长编译时间。
错误信息难以理解模板相关编译错误通常非常冗长、复杂。由于模板的类型推演和实例化过程涉及多层逻辑,一旦出错,错误信息可能包含大量模板细节,使开发者难以快速定位问题根源,增加调试难度。

🔴四、模板应用案例深度剖析

(一)STL 与模板的紧密联系

STL 是 C++ 标准模板库,它堪称模板应用的典范。STL 包含容器(如 vectorlistmap 等)、迭代器、算法(如 sortfind 等)和函数对象等组件,几乎所有组件都基于模板实现。

vector 容器为例:

#include <vector>
using namespace std;
int main()
{vector<int> vecInt;vecInt.push_back(10);vecInt.push_back(20);vector<double> vecDouble;vecDouble.push_back(3.14);return 0;
}

vector 是一个类模板,通过模板参数指定存储元素的类型。vector<int> 是处理 int 类型的动态数组,vector<double> 则处理 double 类型。这种基于模板的设计使 STL 具有高度通用性和灵活性,能适用于各种数据类型,极大提升了编程效率。

(二)自定义泛型算法

借助模板,我们可轻松编写通用算法。以下是一个通用的数组遍历算法示例:

template<typename T>
void Traverse(T* arr, size_t size)
{for (size_t i = 0; i < size; ++i){cout << arr[i] << " ";}cout << endl;
}
int main()
{int intArr[] = { 1, 2, 3, 4, 5 };Traverse(intArr, 5);double doubleArr[] = { 1.1, 2.2, 3.3, 4.4, 5.5 };Traverse(doubleArr, 5);return 0;
}

Traverse 函数模板可处理任意类型数组,只要数组元素支持 << 操作符。这体现了模板在算法设计中的强大能力,使算法与数据类型解耦,提高代码的通用性和可维护性。

🔴五、模板与面向对象编程的融合

(一)模板类与继承、多态的结合

模板类可与继承、多态结合,实现更复杂的设计模式。例如,可创建一个模板基类,定义通用接口,然后通过继承实现特定功能:

template<typename T>
class Base
{
public:virtual void process(T data) = 0;virtual ~Base() {}
};
template<typename T>
class Derived : public Base<T>
{
public:void process(T data) override{cout << "Processing: " << data << endl;}
};

上述代码中,Base 是模板基类,定义了纯虚函数 processDerived 继承自 Base,实现了 process 函数。通过这种结合,我们既能利用模板的泛型特性,又能发挥面向对象编程的多态优势。

(二)模板方法模式的模板实现

模板方法模式是一种行为设计模式,可在方法中定义算法骨架,将某些步骤的实现延迟到子类。利用模板,可实现更灵活的模板方法模式:

template<typename T>
class Algorithm
{
public:void execute(T data){step1(data);step2(data);}
protected:virtual void step1(T data){cout << "Default step1: " << data << endl;}virtual void step2(T data) = 0;
};
template<typename T>
class ConcreteAlgorithm : public Algorithm<T>
{
protected:void step2(T data) override{cout << "Concrete step2: " << data << endl;}
};

Algorithm 模板类中,execute 方法定义了算法骨架,step1 有默认实现,step2 需子类实现。ConcreteAlgorithm 继承并实现了 step2。这种基于模板的模板方法模式,使算法框架更具通用性和扩展性。

🔴六、模板的高级特性探索

(一)模板元编程( TMP )

模板元编程是一种在编译时期进行计算和执行逻辑的技术。它利用模板的递归实例化和特化等特性,在编译阶段完成某些任务。

示例 - 计算斐波那契数列:

template<int N>
struct Fibonacci
{enum { value = Fibonacci<N - 1>::value + Fibonacci<N - 2>::value };
};
template<>
struct Fibonacci<1>
{enum { value = 1 };
};
template<>
struct Fibonacci<2>
{enum { value = 1 };
};
int main()
{cout << Fibonacci<6>::value << endl; // 输出 8return 0;
}

在上述代码中,Fibonacci 模板通过递归特化,在编译时期计算出斐波那契数列的值。当请求 Fibonacci<6>::value 时,编译器会依次推导出 Fibonacci<5>Fibonacci<4> 等,直至到达基础特化版本,最终计算出结果。模板元编程使某些计算在编译时期完成,可优化运行时性能,但也增加了编译复杂度。

(二)可变参数模板

可变参数模板允许函数模板或类模板接受不定数量和类型的参数,提供了更大的灵活性。

示例 - 日志打印函数:

#include <iostream>
#include <string>
using namespace std;
template<typename T>
void Log(const T& value)
{cout << value << endl;
}
template<typename T, typename... Args>
void Log(const T& value, const Args&... args)
{cout << value << ", ";Log(args...);
}
int main()
{Log("Info:", "Name", "John", "Age", 30);return 0;
}

该示例中,Log 函数模板通过可变参数模板接受多个参数。第一个 Log 专门处理单个参数,第二个 Log 处理多个参数,利用递归展开参数包,依次输出每个参数。可变参数模板广泛应用于需要处理不定参数的场景,如日志系统、格式化输出等。

🔴七、模板在实际项目中的最佳实践

(一)合理使用模板提升代码质量

在实际项目中,模板可用于以下场景提升代码质量:

  1. 通用算法实现:如排序、查找等算法,利用模板使算法适用于多种数据类型。
  2. 容器类设计:仿照 STL 容器,设计自己的泛型容器,如自定义链表、哈希表等。
  3. 接口与适配器:通过模板定义通用接口,适配不同第三方库或模块,降低耦合度。

(二)避免模板滥用

模板虽强大,但滥用可能导致代码难以理解和维护。以下情况应避免使用模板:

  1. 简单问题复杂化:若问题有简单直接的解决方案,无需引入模板。例如,仅需处理单一类型时,普通函数即可满足需求,不必使用模板函数。
  2. 性能并非关键且代码可读性重要:在一些对性能要求不高但需快速开发、代码可读性优先的场景,如脚本解析、简单业务逻辑处理,过多模板可能增加阅读难度,此时普通面向对象设计可能更合适。
  3. 团队技术能力有限:若团队成员对模板技术掌握程度不一,大量使用模板可能导致代码维护困难。需根据团队实际情况权衡模板的使用范围。

(三)优化模板代码的策略

为优化模板代码,可采取以下策略:

  1. 限制模板参数数量:过多模板参数会增加代码复杂度和编译时间。尽量减少模板参数,或通过默认参数降低使用难度。
  2. 提供明确的编译错误信息:利用 static_assert 等工具,在编译时期检查模板使用是否正确,给出清晰错误提示。例如:
    template<typename T>
    class MyContainer
    {static_assert(std::is_copy_constructible<T>::value, "Type must be copy constructible");// ...
    };
    
    当模板参数 T 不满足拷贝构造条件时,编译器会输出明确错误信息,而非复杂的模板错误。
  3. 合理使用模板特化:为特殊类型提供特化版本,优化性能或修正行为。但应避免过度特化,防止代码碎片化。例如,为常用基本类型(intdouble 等)特化数学计算模板函数,提升计算效率。

🔴八、模板的未来发展与挑战

(一)C++ 新标准对模板的演进

随着 C++ 语言的不断发展,新标准对模板进行了诸多改进和扩展:

  1. C++11:引入了 variadic templates(可变参数模板),极大增强了模板的灵活性,支持函数和类模板接受任意数量参数,为实现复杂通用库提供了基础。
  2. C++14:进一步完善可变参数模板,使其实用性更强,如放宽了对模板参数推导的限制,简化了模板代码编写。
  3. C++17:引入了 template auto 等特性,使模板函数的编写更加简洁,同时对模板推导进行了优化,提高了编译器对模板代码的理解能力。
  4. C++20:概念(Concepts)正式引入,这是模板发展的重要里程碑。Concepts 允许程序员为模板参数定义约束条件,编译器可根据这些约束检查模板使用是否正确。这有效解决了传统模板中因类型不匹配导致的深奥编译错误,提高了模板代码的可读性和可维护性。例如:
    #include <concepts>
    template<std::Integral T>
    T Add(T a, T b)
    {return a + b;
    }
    
    在此代码中,std::Integral 是一个概念,约束模板参数 T 必须是整数类型。若尝试用非整数类型调用 Add 函数,编译器会给出明确错误提示,而非冗长复杂的模板错误信息。

(二)模板面临的挑战与应对策略

尽管模板技术不断发展,但仍面临诸多挑战:

  1. 编译性能瓶颈:模板的复杂实例化过程对编译器资源消耗巨大,尤其在大型项目中,可能导致编译时间过长。应对策略包括:优化模板代码结构,减少不必要的模板嵌套和特化;使用预编译头文件(PCH)技术,加速头文件中模板代码的编译;选择支持并发编译的现代编译器,如 Clang、GCC 等,提高编译效率。
  2. 学习曲线陡峭:模板涉及众多抽象概念和复杂语法,对新手程序员来说难度较大。项目团队应提供模板技术培训,编写模板编程指南,规范模板使用方式;鼓励从简单模板应用入手,逐步深入学习复杂特性,如从函数模板开始,再学习类模板、模板特化等。
  3. 与遗留代码兼容性问题:在将模板引入遗留系统时,可能因命名冲突、类型不匹配等问题导致兼容性故障。解决方法包括:对遗留代码进行封装,通过适配器模式使其与模板代码协同工作;全面测试模板与遗留代码的交互场景,提前发现并修复潜在问题;采用渐进式重构策略,逐步用模板替换遗留代码中的重复逻辑,而非一次性大规模改造。

🔴九、模板与其他编程语言泛型机制的对比

(一)与 Java 泛型对比

特性对比维度C++ 模板Java 泛型
实现机制编译时期代码生成,基于参数化类型生成具体代码类型擦除,编译器在编译时期移除类型参数,运行时所有实例均为原始类型
性能开销无运行时开销,针对特定类型生成优化代码由于类型擦除,可能因类型检查和强制转换增加轻微运行时开销
类型安全编译时期严格检查,但模板特化和元编程可能导致复杂错误编译时期检查,运行时通过类型擦除保证类型安全,但会丢失类型信息
功能灵活性支持复杂类型计算、模板特化、元编程等高级特性主要用于类型安全的集合操作,功能相对有限,不支持原始类型作为类型参数
错误信息错误信息可能冗长、难以理解,尤其是复杂模板错误信息相对简洁,但类型擦除可能导致某些类型相关错误在运行时期才发现

(二)与 C# 泛型对比

特性对比维度C++ 模板C# 泛型
实现机制编译时期代码生成运行时期由 CLR(公共语言运行时)处理泛型,共享运行时表示
性能开销无运行时开销较低运行时开销,CLR 对泛型类型进行优化处理
类型安全编译时期严格检查,但允许更多低层操作编译时期和运行时期共同保证类型安全,严格类型检查
功能灵活性功能强大,支持多种高级特性功能适中,支持基本泛型编程需求,不允许某些不安全操作
与值类型兼容性支持值类型和引用类型,包括基本类型支持值类型和引用类型,但处理值类型时可能涉及装箱拆箱开销

🔴十、总结与展望

C++ 模板作为一项强大的技术,为程序员提供了实现泛型编程、提升代码复用性和灵活性的有力工具。从基础的函数模板和类模板,到进阶的非类型模板参数、模板特化,再到复杂的模板元编程和可变参数模板,模板体系的深度和广度令人惊叹。在实际项目中,合理运用模板可显著提高开发效率、构建高效灵活的系统;但同时,我们也要清醒认识到模板带来的代码膨胀、编译时间增加和复杂错误信息等问题,需谨慎权衡利弊。

随着 C++ 语言的持续发展,模板技术也在不断完善。从 C++11 的可变参数模板,到 C++20 的概念(Concepts),每一次演进都致力于解决模板使用中的痛点,提升模板的易用性和安全性。未来,我们有理由相信模板技术将在更多领域发挥关键作用,为软件开发带来新的突破。

对于广大 C++ 开发者而言,深入掌握模板知识既是挑战也是机遇。在不断学习和实践中,我们应遵循以下原则:

  • 适度使用模板:根据项目实际需求和技术团队能力,合理选择模板应用场景,避免过度设计。
  • 注重代码可读性:编写模板代码时,添加详细注释,遵循一致的命名规范,必要时提供非模板示例代码辅助理解。
  • 持续关注模板发展:跟踪 C++ 新标准中模板相关特性,及时将新技术应用到项目中,提升代码质量和开发效率。

总之,C++ 模板是一座值得深入挖掘的技术宝藏,期待每位开发者都能在其中找到属于自己的价值,编写出更优秀、更高效的 C++ 程序。
员提供了实现泛型编程、提升代码复用性和灵活性的有力工具。从基础的函数模板和类模板,到进阶的非类型模板参数、模板特化,再到复杂的模板元编程和可变参数模板,模板体系的深度和广度令人惊叹。在实际项目中,合理运用模板可显著提高开发效率、构建高效灵活的系统;但同时,我们也要清醒认识到模板带来的代码膨胀、编译时间增加和复杂错误信息等问题,需谨慎权衡利弊。

随着 C++ 语言的持续发展,模板技术也在不断完善。从 C++11 的可变参数模板,到 C++20 的概念(Concepts),每一次演进都致力于解决模板使用中的痛点,提升模板的易用性和安全性。未来,我们有理由相信模板技术将在更多领域发挥关键作用,为软件开发带来新的突破。

对于广大 C++ 开发者而言,深入掌握模板知识既是挑战也是机遇。在不断学习和实践中,我们应遵循以下原则:

  • 适度使用模板:根据项目实际需求和技术团队能力,合理选择模板应用场景,避免过度设计。
  • 注重代码可读性:编写模板代码时,添加详细注释,遵循一致的命名规范,必要时提供非模板示例代码辅助理解。
  • 持续关注模板发展:跟踪 C++ 新标准中模板相关特性,及时将新技术应用到项目中,提升代码质量和开发效率。

总之,C++ 模板是一座值得深入挖掘的技术宝藏,期待每位开发者都能在其中找到属于自己的价值,编写出更优秀、更高效的 C++ 程序。

相关文章:

《C++探幽:模板从初阶到进阶》

文章目录 :red_circle:一、模板基础&#xff1a;开启泛型编程之门&#xff08;一&#xff09;泛型编程的必要性&#xff08;二&#xff09;函数模板1. 函数模板概念2. 函数模板定义格式3. 函数模板原理4. 函数模板实例化5. 模板参数匹配原则 &#xff08;三&#xff09;类模板1…...

画立方体软件开发笔记 js three 投影 参数建模 旋转相机 @tarikjabiri/dxf导出dxf

gitee&#xff1a; njsgcs/njsgcs_3d mainwindow.js:4 Uncaught SyntaxError: The requested module /3dviewport.js does not provide an export named default一定要default吗 2025-05-10 14-27-58 专门写了个代码画立方体 import{ scene,camera,renderer} from ./3dviewp…...

LVGL图像导入和解码

LVGL版本&#xff1a;8.1 概述 在LVGL中&#xff0c;可以导入多种不同类型的图像&#xff1a; 经转换器生成的C语言数组&#xff0c;适用于页面中不常改变的固定图像。存储系统中的外部图像&#xff0c;比较灵活&#xff0c;可以通过插卡或从网络中获取&#xff0c;但需要配置…...

Win10无法上网:Windows 无法访问指定设备、路径或文件。你可能没有适当的权限访问该项目找不到域 TEST 的域控制器DNS 解析存在问题

目录 一.先看问题 二.解决问题 三.补充备用 一.先看问题 Win08有网且已经加入域 Win10无网并且找不到域&#xff08;说明&#xff1a;Win10我之前已经加入过域的&#xff0c;并且能够上网&#xff0c;但每次在宿舍和教室切换校园网&#xff0c;就会导致只有Win10无网&#…...

开疆智能Canopen转Profinet网关连接工博士GBS20机器人配置案例

本案例是介绍将支持canopen通信协议的机器人机器人接入到西门子Profinet网络中&#xff0c;由于两种协议不能直接通讯&#xff0c;故选择了canopen转Profinet网关进行通讯协议转换。 配置过程&#xff1a; 首先打开Profinet主站配置软件&#xff0c;新建项目并导入网关GSD文件…...

物业企业绩效考核制度与考核体系

物业企业绩效考核制度旨在通过建立科学、公正的绩效管理体系,提升员工的工作效率、激发团队的潜力,并通过对绩效结果的合理运用来推动公司可持续发展。该制度覆盖了公司全体员工,并明确规定了不同岗位、不同部门的考核内容、周期以及绩效考核的标准操作流程。通过月度、季度…...

expo多网络请求设定。

在使用 npx expo start 启动 Expo 开发服务器时&#xff0c;你可以通过设置网络模式来控制你的应用如何连接到开发服务器。Expo 提供了几种网络模式供你选择&#xff1a; LAN (Default): 这是默认模式。在这种模式下&#xff0c;你的应用会通过本地局域网 (LAN) 连接到你的开发…...

M0基础篇之ADC

本节课使用到的例程 一、例程基本配置的解释 在例程中我们只使用到了PA25这一个通道&#xff0c;因此我们使用的是Single这个模式&#xff0c;也就是我们在配置模式的时候使用的是单一转换。 进行多个通道的测量我们可以使用Sequence这个模式。 二、例程基本代码讲解 DL_ADC12_…...

Cadence 高速系统设计流程及工具使用三

5.8 约束规则的应用 5.8.1 层次化约束关系 在应用约束规则之前&#xff0c;我们首先要了解这些约束规则是如何作用在 Cadence 设计对象上的。Cadence 中对设计对象的划分和概念&#xff0c;如表 5-11 所示。 在 Cadence 系统中&#xff0c;把设计对象按层次进行了划分&#…...

gitkraken 使用教程

一、安装教程 安装6.5.3&#xff0c;之后是收费的&#xff0c;Windows版免安装 二、使用教程 0. 软件说明 gitkraken是一个git本地仓库管理软件&#xff0c;可以管理多个仓库&#xff0c;并且仓库可以属于多个网站多个账户。 1. 克隆仓库 选择要克隆到什么位置&#xff0…...

抖音视频上传功能测试全维度拆解——从基础功能到隐藏缺陷的深度挖掘

一、核心功能测试&#xff08;Happy Path&#xff09; 文件基础验证 支持格式&#xff1a;MP4/MOV/AVI等&#xff08;含H.264/H.265编码组合验证&#xff09; 分辨率兼容性&#xff1a;720p→8K的渐进式测试&#xff08;重点验证竖屏9:16适配&#xff09; 时长边界&#xff1…...

基于PE环境搭建及调试S32K312

0、简介 本文基于S32K312 介绍PE的使用流程&#xff0c;主要是记录开发流程&#xff1a; MCU&#xff1a;NXP S32k312-100pin 编辑器&#xff1a;S32 Design Studio for S32 Platform 3.5 仿真器&#xff1a;PE USB Multilink Universal REV-E PE和jlink不一样&#xff0c…...

Autoware播放提示音

播放提示音 1、修改sound_player.yaml src/autoware/utilities/sound_player/scripts/sound_player.yaml start : ~/Autoware/install/sound_player/share/sound_player/start.wav stop : ~/Autoware/install/sound_player/share/sound_player/stop.wav red …...

学习黑客5 分钟深入浅出理解cron [特殊字符]

5 分钟深入浅出理解cron &#x1f552; 大家好&#xff01;今天我们将探索Linux系统中的cron——这个强大的定时任务调度工具&#xff0c;它允许用户自动执行周期性任务。在网络安全领域&#xff0c;尤其是在TryHackMe平台上的CTF挑战中&#xff0c;理解cron不仅是系统管理的基…...

Qt解决自定义窗口样式不生效问题

方法一&#xff1a; this->setAttribute(Qt::WA_StyledBackground, true); 方法二&#xff1a; 将类继承QWidget 改成继承 QFrame class MyWidget : public QFrame {} 方法三&#xff1a;重新实现QWidget的paintEvent函数时&#xff0c;使用QStylePainter绘制。 void p…...

redis未授权访问

redis是高速缓存型数据库&#xff0c;主要用户缓存一些频繁使用的数据来缓解数据库的访问压力。而redis未授权访问漏洞是因为redis数据库使用的过程中没有设定密码&#xff0c;任何人都可以直接连接数据库&#xff0c;这既是未授权访问&#xff0c;这是个通用漏洞&#xff0c;部…...

.Net HttpClient 使用准则

HttpClient 使用准则 System.Net.Http.HttpClient 类用于发送 HTTP 请求以及从 URI 所标识的资源接收 HTTP 响应。 HttpClient 实例是应用于该实例执行的所有请求的设置集合&#xff0c;每个实例使用自身的连接池&#xff0c;该池将其请求与其他请求隔离开来。 从 .NET Core …...

Eclipse 插件开发 6 右键菜单

Eclipse 插件开发 6 右键菜单 1 plugin.xml2 SampleHandler.java3 Activator.java 1 plugin.xml <?xml version"1.0" encoding"UTF-8"?> <?eclipse version"3.4"?> <plugin><!-- 定义命令 --><extension point&…...

MGP-STR:用于场景文本识别的多粒度预测

摘要 场景文本识别&#xff08;Scene Text Recognition&#xff0c;简称STR&#xff09;多年来一直是计算机视觉领域的研究热点。为了解决这一具有挑战性的问题&#xff0c;研究者们陆续提出了许多创新方法&#xff0c;近期将语言知识引入STR模型已成为一项重要趋势。在本研究…...

DAMA语境关系图汇总及考前须知

写在前面 1.考前须知 2.梳理彩色详细的语境关系图&#xff0c;方便理解与深化 1.考前须知 单选题10道题&#xff0c;每题1分&#xff0c;满分10分&#xff0c; 多选题15道题&#xff0c;每题2分&#xff0c;满分30分&#xff0c; 解答题6道&#xff0c;每题10分&#xff…...

Vue.js框架的优缺点

别再让才华被埋没&#xff0c;别再让github 项目蒙尘&#xff01;github star 请点击 GitHub 在线专业服务直通车GitHub赋能精灵 - 艾米莉&#xff0c;立即加入这场席卷全球开发者的星光革命&#xff01;若你有快速提升github Star github 加星数的需求&#xff0c;访问taimili…...

【Pandas】pandas DataFrame corr

Pandas2.2 DataFrame Computations descriptive stats 方法描述DataFrame.abs()用于返回 DataFrame 中每个元素的绝对值DataFrame.all([axis, bool_only, skipna])用于判断 DataFrame 中是否所有元素在指定轴上都为 TrueDataFrame.any(*[, axis, bool_only, skipna])用于判断…...

【金仓数据库征文】金融行业中的国产化数据库替代应用实践

【引言】 随着国内技术的进步&#xff0c;越来越多的金融机构开始尝试将传统的商业数据库替换为国产化数据库。金仓数据库&#xff08;KingbaseES&#xff0c;简称KES&#xff09;凭借其高性能、稳定性和灵活的架构&#xff0c;逐步成为金融行业数据库替代的首选方案。本文将探…...

《基于人工智能的智能客服系统:技术与实践》

一、引言 在数字化时代&#xff0c;客户服务已成为企业竞争的关键领域之一。随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;智能客服系统逐渐成为企业提升服务质量和效率的重要工具。智能客服不仅能够快速响应客户咨询&#xff0c;还能通过自然语言处理&am…...

关于汇编语言与程序设计——单总线温度采集与显示的应用

一、实验要求 (1)握码管的使用方式 (2)掌握DS18B20温度传感器的工作原理 (3)掌握单总线通信方式实现 MCU与DS18B20数据传输 二、设计思路 1.整体思路 通过编写数码管显示程序和单总线温度采集程序&#xff0c;结合温度传感报警&#xff0c;利用手指触碰传感器&#xff0c;当…...

管道-验证和转换

管道-验证和转换 什么是管道管道的简单使用验证转换ParseIntPipeParseArrayPipe其他代码进度什么是管道 英雄联盟的老鼠说过一句话,条条管道通我家。管道一的脏水流到了管道二,管道二的脏水由于太脏了有杂物,堵住了去管道三的入口,所以通过不了(验证),去了管道四净化了下…...

多层嵌套子查询

在优化多层嵌套子查询的 Hive SQL 时&#xff0c;除了常见的谓词下推、分区裁剪、WITH 子句复用和动态分区优化&#xff0c;还可以通过 抽象语法树&#xff08;AST&#xff09;分析 和 基于历史的优化&#xff08;HBO&#xff09; 进一步优化。以下是结合所有技术方向的完整方案…...

[架构之美]从零开始整合Spring Boot与Maven(十五)

[架构之美]从零开始整合Spring Boot与Maven&#xff08;十五&#xff09; 摘要&#xff1a;本文手把手教你通过Maven快速构建Spring Boot项目&#xff0c;涵盖项目初始化、自动配置、依赖管理及打包部署全流程&#xff0c;并附赠常见避坑指南。适合需要快速搭建企业级项目的开…...

第21天打卡

何时使用降维&#xff1f; 1.数据可视化 高维数据难以直接可视化&#xff08;如超过3维&#xff09;&#xff0c;通过降维&#xff08;如PCA、t-SNE、UMAP&#xff09;投影到2D/3D空间&#xff0c;揭示数据分布、聚类或流形结构。 适用算法&#xff1a;t-SNE&#xff08;非线…...

【小记】excel vlookup一对多匹配

一个学生报四门课&#xff0c;输出每个学生课程 应用概述操作预处理数据计数指令 COUNTIFS进行一对多匹配 vlookup 应用概述 应用场景&#xff1a;学生报名考试&#xff0c;需要整理成指定格式&#xff0c;发给考试院。 一个学生最多报考四门 格式实例&#xff1a;准考证号 …...

前端项目中单元测试与集成测试的管理实践

前端项目中单元测试与集成测试的管理实践 在现代前端工程化中&#xff0c;单元测试&#xff08;Unit Test&#xff09;和集成测试&#xff08;Integration Test&#xff09;已成为保障项目质量的重要手段。合理地组织和管理测试代码&#xff0c;不仅有助于持续集成&#xff0c…...

亿级流量系统架构设计与实战(六)

微服务架构与网络调用 当某个业务从单体服务架构转变为微服务架构后,多个服务之间会通过网络调用形式形成错综复杂的依赖关系。 在微服务架构中 , 一个微服务正常工作依赖它与其他微服务之间的多级网络调用。 网络是脆弱的 , RPC 请求有较大的概率会遇到超时 、 抖动 、 断…...

记录踩过的坑-金蝶云苍穹平台-轻分析和轻报表(慢慢更新)

未发现AppIdName(qing rpt)服务或访问服务网络异常 前提是有许可和权限。 去console&#xff08;云基础平台控制台&#xff09;&#xff0c;点击服务管理&#xff0c;编辑mservice-更新升级-环境变量&#xff0c;在appIds里增加qing_rpt 查看数据库 如果是采用公共数据源连接…...

Java并发编程,从线程安全到死锁避免的实战解析

Java并发编程是构建高性能系统的核心技能,但也伴随着复杂的挑战。本文通过实际代码示例,系统讲解线程安全、死锁、资源竞争等常见问题的解决方案,并深入探讨如何利用Java并发工具包(java.util.concurrent)构建健壮的并发程序。 一、线程安全问题与解决方案 1.1 共享资源的…...

基于Python的在线教育平台的设计与实现

标题:基于Python的在线教育平台的设计与实现 内容:1.摘要 随着互联网技术的飞速发展&#xff0c;在线教育平台成为了教育领域的重要组成部分。本研究的目的是设计并实现一个基于Python的在线教育平台&#xff0c;以满足用户多样化的学习需求。方法上&#xff0c;采用Python语言…...

多线程获取VI模块的YUV数据

一.RV1126 VI模块采集摄像头YUV数据的流程 step1&#xff1a;VI模块初始化 step2&#xff1a;启动VI模块工作 step3&#xff1a;开启多线程采集VI数据并保存 1.1初始化VI模块&#xff1a; VI模块的初始化实际上就是对VI_CHN_ATTR_S的参数进行设置、然后调用RK_MPI_VI_SetC…...

通过推测搜索加速大型语言模型推理 (SpecSearch) 论文总结

通过推测搜索加速大型语言模型推理 (SpecSearch) 论文总结 1. 研究背景与任务 基于树搜索的推理方法(如思维树Tree-of-Thoughts)通过探索多个中间推理步骤&#xff0c;显著增强了大型语言模型(LLMs)的推理能力。然而&#xff0c;这些方法需要生成大量推理思考&#xff0c;导致…...

从代码学习深度学习 - 语义分割和数据集 PyTorch版

文章目录 前言什么是语义分割?图像分割和实例分割Pascal VOC2012 语义分割数据集Pascal VOC2012 语义分割数据集介绍基本信息语义分割部分特点数据格式评价指标应用价值数据集获取使用提示辅助工具代码 (`utils_for_huitu.py`)读取数据预处理数据自定义语义分割数据集类读取数…...

【计算机视觉】OpenCV实战项目:Deep Machine Learning Tutors:基于OpenCV的实时面部识别系统深度解析

Deep Machine Learning Tutors&#xff1a;基于OpenCV的实时面部识别系统深度解析 1. 项目概述2. 技术原理2.1 面部识别流程2.2 关键技术组件2.2.1 Haar级联分类器2.2.2 深度特征提取 3. 项目实现细节3.1 系统架构3.2 核心算法实现3.2.1 人脸检测3.2.2 实时处理流水线 4. 项目运…...

OSCP - Proving Grounds - EvilBox-One

主要知识点 类似黑盒测试&#xff0c;毫无线索的情况下只能去猜&#xff0c;如果是php文件则会比较容易达到入侵的目的即使有php文件了&#xff0c;由于不知道代码&#xff0c;只能测试一下有没有文件包含漏洞所以反正没线索的时候&#xff0c;就只能猜 具体步骤 nmap扫描&a…...

初识Linux · 传输层协议TCP · 下

目录 前言&#xff1a; 滑动窗口和流量控制机制 流量控制 滑动窗口 1.滑动窗口如何移动 2.滑动窗口的大小如何变化的 3.如果发生了丢包如何解决&#xff08;快重传&#xff09; 拥塞控制 延迟应答 面向字节流 RST PSH URG 什么是 PSH&#xff1f; 什么是 URG&…...

OpenCv实战笔记(4)基于opencv实现ORB特征匹配检测

一、原理作用 ORB 原理&#xff08;Oriented FAST and Rotated BRIEF&#xff09;&#xff1a; 特征点检测&#xff1a;使用 FAST 算法检测角点&#xff08;关键点&#xff09;。 方向计算&#xff1a;为每个关键点分配主方向&#xff0c;增强旋转不变性。 特征描述&#xff1a…...

LeetCode LCR 007. 三数之和 (Java)

题目描述 给定一个整数数组 nums&#xff0c;判断是否存在三个元素 a, b, c&#xff0c;使得 a b c 0&#xff1f;找出所有满足条件且不重复的三元组。 解题思路 核心方法&#xff1a;排序 双指针 排序&#xff1a;首先将数组排序&#xff0c;便于后续去重和双指针操作。…...

Spark的三种部署模式及其特点与区别

Spark支持多种集群部署模式&#xff0c;主要分为以下三类&#xff1a; 部署模式特点适用场景资源管理依赖Local模式单机运行&#xff0c;所有进程&#xff08;Driver、Executor&#xff09;在同一个JVM中开发调试、小规模数据测试无集群资源管理&#xff0c;仅本地线程模拟无需…...

2505d,d的借用检查器

void func(scope ref int*) {}unique(int*) a ...; assert(a !is null);unique(int*) b a; assert(a is null); assert(b !is null);func(b); // ok用live作为检查器,不必有断定了. int* a ...; int* b a; // 所有权转至b *a 3; // 不能再用a.编译器保证约束指针. live…...

前端EXCEL插件,智表ZCELL产品V3.0 版本发布,底层采用canvas全部重构,功能大幅扩展,性能极致提升,满足千万级单元格加载

本次更新是底层全部重构&#xff0c;按照现代浏览器要求&#xff0c;采用canvas方式进行了重构&#xff0c;预留了将来扩展空间&#xff0c;特别是在大数据量性能提升方面有了较大提升&#xff0c;可以满足千万级单元格加载&#xff0c;欢迎大家体验使用。 体验地址&#xff1…...

如何理解编程中的递归、迭代与回归?

作为编程初学者&#xff0c;递归、迭代和回归这三个概念常常让人感到困惑。本文将通过生活化的比喻、Python代码示例和直观的对比&#xff0c;帮助你彻底理解这三个重要概念及其应用场景。 一、从生活比喻理解核心概念 1. 递归&#xff08;Recursion&#xff09;—— 俄罗斯套…...

【金仓数据库征文】学校AI数字人:从Sql Server到KingbaseES的数据库转型之路

摘要&#xff1a;本文围绕学校 AI 数字人项目从 Sql Server 数据库替换至 KingbaseES 数据库的实践展开&#xff0c;涵盖迁移背景、两种数据库对比、替换实施步骤、应用效果展示、问题与解决措施等多方面内容&#xff0c;为教育领域类似项目提供了详实参考。 目录 1.背景与需求…...

stm32 lcd绘制波形和频谱

一、项目准备 主要利用LCD驱动中的画点和画连线函数&#xff0c;驱动是正点原子给我写好了的画点和画线的函数等些相关函数 void LCD_Draw_Circle(u16 x0,u16 y0,u8 r); //画圆 void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2); //画线 二、画波形图函数实…...

深入理解卷积神经网络的输入层:数据的起点与预处理核心

内容摘要 本文围绕卷积神经网络输入层展开&#xff0c;详细介绍其在网络中的重要作用&#xff0c;包括接收不同领域数据的形式及传递数据的过程。深入解读数据预处理的关键操作&#xff0c;如去均值、归一化和PCA/白化。助力读者透彻理解输入层&#xff0c;为构建高效卷积神经…...