网站建立的步骤是,wordpress 回复 慢,网站前台模块包括什么,wordpress设置自定义就出现404模板与泛型编程常用技巧 目录一、基础阶段1.1 函数模板1.2 类模板1.3 模板特化与偏特化1.4模板编译模型1.5 变量模板1.6 别名模板1.7 模板模板参数 二、中级阶段2.1 SFINAE2.2 enable_if#xff1a;SFINAE应用2.3 void_t技术#xff1a;SFINAE应用2.4 萃取2.5 可变参数模板2.… 模板与泛型编程常用技巧 目录一、基础阶段1.1 函数模板1.2 类模板1.3 模板特化与偏特化1.4模板编译模型1.5 变量模板1.6 别名模板1.7 模板模板参数 二、中级阶段2.1 SFINAE2.2 enable_ifSFINAE应用2.3 void_t技术SFINAE应用2.4 萃取2.5 可变参数模板2.6 完美转发 三、高级阶段3.1 C模板设计模式 四、模板实践4.1智能指针实现 目录
一、基础阶段
1.1 函数模板
templatetypename T
T Max(const T t1, const T t2)
{return t1 t2 ? t2 : t1;
}templatetypename T
void Swap(T t1, T t2)
{T temp std::move(t1);t1 std::move(t2);t2 std::move(temp);}1.2 类模板
templatetypename T
struct Stack
{
private:vectorT elments;
public:void Push(const T obj){elments.push_back(obj);}void Pop(){if (elments.size() 0){elments.pop_back();}else{throw out_of_range(empty stack);}}T GetTop(){if (elments.size() 0){return elments.back();}else{throw out_of_range(empty stack);}}};templatetypename T,size_t nSize
class Array
{
private:T data[nSize];
public:T operator[](int nIndex){return data[nIndex];}
};int main()
{Arrayint, 5 a;for (int i 0;i5;i){a[i] i 1;cout a[i] ;}system(pause);return 0;
}结果
1.3 模板特化与偏特化
模板特化Template Specialization和偏特化Partial Specialization是C模板编程中的高级特性允许你为特定类型或类型组合提供特殊的模板实现 模板特化 模板特化是指为模板的特定参数提供完全不同的实现。分为函数模板特化和类模板特化。
函数模板特化
// 通用模板
template typename T
void printType() {std::cout Generic type\n;
}// 特化版本 - 针对int类型
template
void printTypeint() {std::cout int type\n;
}// 使用示例
printTypedouble(); // 输出: Generic type
printTypeint(); // 输出: int type类模板特化
// 通用模板
template typename T
class Container {
public:void describe() {std::cout Generic container\n;}
};// 特化版本 - 针对char类型
template
class Containerchar {
public:void describe() {std::cout Character container\n;}
};// 使用示例
Containerdouble c1;
c1.describe(); // 输出: Generic containerContainerchar c2;
c2.describe(); // 输出: Character container模板偏特化 偏特化也称为部分特化允许你为模板的部分参数提供特殊实现。注意偏特化只适用于类模板不适用于函数模板。
基本偏特化
// 通用模板
template typename T, typename U
class Pair {
public:void describe() {std::cout Generic pair\n;}
};// 偏特化 - 当两个类型相同时
template typename T
class PairT, T {
public:void describe() {std::cout Pair of same types\n;}
};// 使用示例
Pairint, double p1;
p1.describe(); // 输出: Generic pairPairfloat, float p2;
p2.describe(); // 输出: Pair of same types// 通用模板
template typename T
class Box {
public:void describe() {std::cout Box of value type\n;}
};// 偏特化 - 针对指针类型
template typename T
class BoxT* {
public:void describe() {std::cout Box of pointer type\n;}
};// 使用示例
Boxint b1;
b1.describe(); // 输出: Box of value typeBoxint* b2;
b2.describe(); // 输出: Box of pointer type结果 多参数偏特化
// 通用模板
template typename T, typename U, typename V
class Triple {
public:void describe() {std::cout Generic triple\n;}
};// 偏特化 - 当第一个和第三个类型相同时
template typename T, typename U
class TripleT, U, T {
public:void describe() {std::cout Triple with first and last same type\n;}
};// 使用示例
Tripleint, double, char t1;
t1.describe(); // 输出: Generic tripleTriplefloat, int, float t2;
t2.describe(); // 输出: Triple with first and last same type示例封装一个判断是否为指针的工具
templatetypename T
struct Is_pointer {static constexpr bool value false;
};templatetypename T
struct Is_pointerT * {static constexpr bool value true;
};int main()
{cout Is_pointerint::value endl;cout Is_pointerint*::value endl;system(pause);return 0;
}结果
1.4模板编译模型
模板编译模型是指C编译器处理模板代码的方式和规则它决定了模板如何被实例化、链接以及最终生成可执行代码。 包含模型- 最常用 核心思想模板定义必须在使用它的每个翻译单元中都可见 特点
模板的声明和定义都放在头文件中每个使用模板的源文件都会包含完整定义编译器在每个翻译单元实例化所需特化
示例
// vector.h
template typename T
class Vector {
public:void push_back(const T value) {// 实现直接写在头文件中}
};显式实例化模型 核心思想提前显式声明需要的模板实例化 ** mytemplate.h**
#pragma once
// mytemplate.h
template typename T
T add(T a, T b); // 只有声明mytemplate.cpp
#include Mytemplate.h
// mytemplate.cpp
template typename T
T add(T a, T b) { return a b; }// 显式实例化
template int addint(int, int);
template double adddouble(double, double);main.cpp
#include iostream
#include Mytemplate.h
using namespace std;int main()
{coutadd(100, 200) endl;cout add(12.3, 22.65) endl;system(pause);return 0;
}特点
模板定义可放在.cpp文件需预先知道所有需要的实例化减少重编译但灵活性低
1.5 变量模板
变量模板的基本定义形式
templatetypename T
constexpr T pi T(3.1415926535897932385L); // 变量模板声明和定义使用方式
float f pifloat; // 3.14159265f
double d pidouble; // 3.141592653589793
long double ld pilong double; // 3.1415926535897932385L基本用途 (1) 类型相关的常量
#include numerictemplatetypename T
constexpr T max_value std::numeric_limitsint::max();int main()
{cout max_valueint endl;cout max_valuedouble endl;system(pause);return 0;
}结果 (2) 简化类型特征访问
templatetypename T
constexpr bool Is_integral_v std::is_integralT::value;int main()
{static_assert(Is_integral_vint); // 通过static_assert(!Is_integral_vfloat); // 通过system(pause);return 0;
}1.6 别名模板
别名模板是C11引入的一项重要特性它允许我们为模板创建类型别名极大地简化了复杂类型表达式的书写提高了代码的可读性和可维护性。 别名模板Alias Template是一种可以参数化的typedef它能够为模板类型创建别名
基本语法
template模板参数列表
using 别名 类型表达式;templatetypename T
using Vec std::vectorT; // VecT 是 std::vectorT 的别名基本使用
Vecint v1; // 等价于 std::vectorint
Vecstd::string v2; // 等价于 std::vectorstd::string1.7 模板模板参数
模板模板参数是指接受一个类模板作为参数的模板参数。它允许你在不指定具体类型的情况下传递整个模板作为参数。
基本语法
template template typename class Container
class Wrapper {Containerint data; // 使用传入的模板实例化
};使用示例
template typename T
class MyVector { /*...*/ };WrapperMyVector w; // 将MyVector模板作为参数传递现在有一个需求创建一个TyClass的类模板这个类模板有一个成员变量myc,这个成员变量是一个容器可能是一个vector或者list等。现在希望在实例化这个类模板时候能够通过模板参数指定myc是什么类型的容器以及指定这个容器中所装的元素类型。比如
TyClassint,vector myvectobj;
TyClassdouble,list mylistobj;实现代码
templatetypename T,templatetypename
class Container std::vectorclass TyClass
{
private:ContainerT myc;
public:void Push(const T obj){myc.push_back(obj);}void Print(){for (const auto node :myc){cout node endl;}}
};int main()
{TyClassint tc;tc.Push(1);tc.Push(2);tc.Push(3);tc.Push(4);tc.Print();system(pause);return 0;
}结果
二、中级阶段
2.1 SFINAE
SFINAESubstitution Failure Is Not An Error是C模板元编程中的核心机制它允许编译器在模板参数替换失败时优雅地忽略该候选而非报错。
templateclass T
void f(typename T::type i) {}; // 当T没有::type成员时触发SFINAEstruct X { using type int; };
struct Y {};int main()
{fX(0); // 匹配fY(0); // SFINAE忽略若无其他重载则报未找到匹配函数system(pause);return 0;
}结果
编译器并不认为这个函数模板有错这就是所谓的“替换失败并不是一个错误”对于Y类型并没有type,但是对于其他的类型可能就存在,比如X。但是为什么会报“未找到匹配的重载函数”呢这是由于函数模板不匹配编译器又找不到其他适合的f(),所以编译器才报错.
2.2 enable_ifSFINAE应用
标准定义
templatebool B, class T void
struct enable_if {};templateclass T
struct enable_iftrue, T { using type T; // 只有当Btrue时才有type成员
};辅助类型别名 (C14起) templatebool B, class T void
using enable_if_t typename enable_ifB, T::type;示例
templatebool b,typename T void
struct enableIF
{};templatetypename T
struct enableIFtrue, T
{using Type T;
};templatetypename T
typename enableIFstd::is_integralT::value, T::Type Incred(T a)
{a;return a;
}int main()
{cout Incred(12) endl;;//cout Incred(12.2) endl; SFINAEsystem(pause);return 0;
}结果
2.3 void_t技术SFINAE应用
std::void_t是C17中引入的它其实是一个别名模板源码非常简单大概如下
templatetpename...Args
using void_t void;示例
struct hasType {using intType int;void fun() {}
};struct noType {void fun() {}
};
//泛化版本
templatetypename T,typename U void_t
struct HasTypeMem :std::false_type
{};//特化版本
templatetypename T
struct HasTypeMemT, std::void_ttypename T::intType :std::true_type
{};int main()
{ cout HasTypeMemnoType::value endl;cout HasTypeMemhasType::value endl;system(pause);return 0;
}结果
SFINAE机制:
如果 T 没有 intTypetypename T::intType会导致替换失败但这不是错误编译器会回退到泛化版本false_type。如果 T 有 intType替换成功选择特化版本true_type。
2.4 萃取
类型萃取是一种编译时类型检查与操作技术通过模板类和模板特化实现主要用于
检查类型特性如是否为指针、是否为算术类型等修改类型特性如移除const、添加引用等根据类型特性实现条件编译
类型分类检查
std::is_voidT // 是否为void类型
std::is_integralT // 是否为整型
std::is_floating_pointT // 是否为浮点型
std::is_arrayT // 是否为数组类型修饰检查
std::is_constT // 是否有const限定
std::is_pointerT // 是否为指针
std::is_referenceT // 是否为引用类型关系
std::is_sameT, U // 类型是否相同
std::is_base_ofBase, Derived // 是否为基类
std::is_convertibleFrom, To // 是否可隐式转换示例
templatetypename T
struct TraitsType;template
struct TraitsTypechar
{using RetType int;
};template
struct TraitsTypeint
{using RetType __int64;
};templatetypename T
auto GetSum(T* begin, T* end)
{using retType typename TraitsTypeT::RetType;cout typeid(T).name() typeid(retType).name() endl;retType sum{};for (;;){sum (*begin);if (begin end){break;}begin;}return sum;}int main()
{int a1[] { 1,3,5,7 };int a2[] { 500000000,500000000,700000000 };char a3[] abc;cout GetSum(a1[0], a1[3]) endl;cout GetSum(a2[0], a2[2]) endl;int nsum (int)GetSum(a3[0], a3[2]);cout nsum endl;system(pause);return 0;
}结果
自己实现is_void
templatetypename T
struct Is_void
{static const int value 0;
};template
struct Is_voidvoid
{static const int value 1;
};int main()
{cout Is_voidint::value endl;cout Is_voidvoid::value endl;system(pause);return 0;
}结果 自己实现is_same
templatetypename T1,typename T2
struct Is_same
{static const int value 0;
};templatetypename T1
struct Is_sameT1,T1
{static const int value 1;
};int main()
{cout Is_sameint,int::value endl;cout Is_samevoid,int::value endl;system(pause);return 0;
}结果
2.5 可变参数模板
可变参数模板是C11引入的一项强大特性允许模板接受任意数量的模板参数。它是实现泛型编程的重要工具。
可变参数模板使用省略号(…)语法来表示可以接受任意数量的参数
templatetypename... Args
class MyClass {};templatetypename... Args
void myFunction(Args... args) {}其中 Args 是模板参数包 args 是函数参数包
使用示例 1.递归展开 最常见的展开方式是递归
void Print()
{cout endl;
}templatetypename T,typename...U
void Print(T ft, U...args)
{cout ft ;Print(args...);
}int main()
{Print(I,love,China,1314);system(pause);return 0;
}结果 2. 使用折叠表达式 (C17) C17引入了折叠表达式简化了可变参数模板的使用
templatetypename...U
auto Sum(U...args)
{return (... args);
}int main()
{auto nSum Sum(1, 2, 3, 4, 66.5);cout nSum endl;system(pause);return 0;
}结果 3. sizeof… 运算符 可以获取参数包中的参数数量
templatetypename T,typename...U
auto Sum2(T ft, U...args)
{if constexpr (sizeof...(args) 0){return ft Sum2(args...);}else{return ft;}
}4.应用场景 元组(Tuple)实现
templatetypename... Types
class Tuple;完美转发
templatetypename... Args
void forwarder(Args... args) {someFunction(std::forwardArgs(args)...);
}工厂函数
templatetypename T, typename... Args
T* create(Args... args) {return new T(args...);
}打印任意数量参数
templatetypename... Args
void log(Args... args) { /*...*/ }2.6 完美转发
完美转发是C11引入的一项重要特性它允许函数模板将其参数无损地转发给其他函数保持原始参数的值类别左值/右值。
完美转发依赖于两个关键特性
右值引用T引用折叠规则Reference Collapsing
格式如下
templatetypename T
void wrapper(T arg) {// 保持arg的值类别转发给targettarget(std::forwardT(arg));
}引用折叠 类型定义 折叠结果 T T T T T T T T
示例
templatetypename T
void func(T param) {cout 传入的是右值 endl;
}templatetypename T
void funcMiddle(T param) {func(std::forwardT(param));
}int main()
{int num 2021;funcMiddle(num);funcMiddle(2022);system(pause);return 0;
}结果
三、高级阶段
3.1 C模板设计模式
策略模式
templatetypename T, typename AllocationPolicy
class ManagedContainer {AllocationPolicy allocator;
public:void* allocate(size_t size) {return allocator.allocate(size);}// ...其他成员函数
};// 内存分配策略
struct MallocPolicy {void* allocate(size_t size) { return malloc(size); }
};struct NewPolicy {void* allocate(size_t size) { return new char[size]; }
};int main()
{// 使用ManagedContainerint, MallocPolicy mc;int *pArray (int *)mc.allocate(100);pArray[0] 1;pArray[1] 2;pArray[2] 3;cout pArray[0] pArray[1] pArray[2] endl;system(pause);return 0;
}奇异递归模板模式
静态多态实现
templatetypename Derived
class Base
{
public:void Interface(){Derived* pDerived static_castDerived*(this);pDerived-impl();}};class Myderived :public BaseMyderived
{
public:void impl(){cout this is Myderived::impl()\n;}
};templatetypename T
void Process(BaseT* pBase)
{pBase-Interface();
}int main()
{// 使用Myderived d;Process(d);system(pause);return 0;
}应用示例
templatetypename T
class Base
{
public:void process(){GetSub()-process_impl();}
private:T* GetSub(){T* pSub static_castT*(this);return pSub;}};class Sub1 :public BaseSub1
{
public:void process_impl(){cout Sub1::process_impl()\n;}~Sub1(){cout ~Sub1()\n;}};class Sub2 :public BaseSub2
{
public:void process_impl(){cout Sub2::process_impl()\n;}~Sub2(){cout ~Sub2()\n;}
};templatetypename T
void Process(BaseT* p)
{p-process();
}int main()
{Sub1* ps1 new Sub1;Sub2* ps2 new Sub2;Process(ps1);Process(ps2);delete ps1;delete ps2;system(pause);return 0;
}结果
四、模板实践
4.1智能指针实现
templatetypename T
class SharedPtr
{
private:T* m_ptr;int* m_pRefCount;mutex* m_mtx;void Release(){(*m_pRefCount)--;if (*m_pRefCount 0){delete m_ptr;m_ptr nullptr;delete m_pRefCount;m_pRefCount nullptr;}}
public:SharedPtr(T* ptr){m_ptr ptr;m_pRefCount new int(1);m_mtx new mutex;}~SharedPtr(){Release();}SharedPtr(const SharedPtrT obj){m_ptr obj.m_ptr;m_pRefCount obj.m_pRefCount;m_mtx obj.m_mtx;m_mtx-lock();(*m_pRefCount);m_mtx-unlock();}SharedPtrT operator(const SharedPtrT obj){if (this ! obj){Release();m_ptr obj.m_ptr;m_pRefCount obj.m_pRefCount;m_mtx obj.m_mtx;m_mtx-lock();(*m_pRefCount);m_mtx-unlock();}return *this;}T* operator-(){return m_ptr;}T operator*(){return *m_ptr;}int UseCount(){return m_ptr ? *m_pRefCount : 0;}};class Ty
{
public:Ty(int a,int b):m_a(a),m_b(b) { cout Ty()\n; }~Ty() { cout ~Ty()\n; }void Print(){cout m_a: m_a m_b: m_b endl;}
private:int m_a;int m_b;
};int main()
{// 使用{SharedPtrTy sp(new Ty(10, 20));sp-Print();cout cout: sp.UseCount() endl;SharedPtrTysp2(sp);cout cout: sp.UseCount() endl;SharedPtrTy sp3 sp2;cout cout: sp.UseCount() endl;sp3-Print();SharedPtrTy sp4(new Ty(1,2));sp4 sp3;cout cout: sp.UseCount() endl;}system(pause);return 0;
}结果