婚礼效果图怎么制作,seo wordpress 主题,wordpress 自己的html,半瓶的wordpress之旅模板泛化、模板特化、所占字节数、继承实现模板展开、using循环命名展开可变参数 模板泛化模板特化模板全特化通过模板偏特化获取类型所占字节数通过模板偏特化和宏获取类型所占字节数...ParamTypes和ParamTypes...的区别 通过继承实现模板展开using 通过using循环命名的方式来… 模板泛化、模板特化、所占字节数、继承实现模板展开、using循环命名展开可变参数 模板泛化模板特化模板全特化通过模板偏特化获取类型所占字节数通过模板偏特化和宏获取类型所占字节数...ParamTypes和ParamTypes...的区别 通过继承实现模板展开using 通过using循环命名的方式来展开可变参数 模板泛化
当前不知道是什么类型调用时才知道是什么类型 advanced.h #pragma once
#include iostream
using namespace std;//泛化:所有的模板参数类型都未定义当使用时才知道
templateclass T1,class T2/* typename ...ParamTypes*///类型和可变参数的类型都不知道
class FHello_Class
{
private:T1 a;T2 b;
};学习.cpp #include iostream
#includeadvanced.hint main()
{FHello_Classint, floatA;return 0;
}模板特化
特化是一种模板技术
模板全特化
必须写一个模板泛化做匹配否则用不了
模板特化是一种将模板参数替换为具体类型或值的过程
#pragma once
#include iostream
using namespace std;//泛化:所有的模板参数类型都未定义当使用时才知道
templateclass T
class FHello_Class
{
private:T1 a;T2 b;
};//特化全特化模板特化是一种将模板参数替换为具体类型或值的过程
template
class FHello_Classint//给定的类型一定是具体的
{};
/*template
class FHello_Class1int, float//因为没有对应的模板泛化所以会报错
{};*///函数全特化
templateclass T
void FunTest()
{};
template
void FunTestint()
{}模板特化分为模板全特化和模板偏特化 全特化Full Specialization和偏特化Partial Specialization是C中模板特化的两种形式。
全特化是指对完整的模板进行特化也就是将模板中的所有参数都替换为具体的类型或值。全特化通过使用特定的类型或值提供完整的特化定义。例如
templatetypename T, int N
class Array
{
public:T elements[N];
};template
class Arrayint, 5
{
public:int elements[5];
};在上面的例子中我们定义了一个通用的模板类 Array包含一个类型参数 T 和一个整数参数 N。然后我们使用全特化对类型参数为 int整数参数为 5 的情况进行了特化。这意味着当我们使用 Arrayint, 5 这个类型时将使用全特化的定义即 Arrayint, 5 类型将有一个 int 类型的数组成员。
偏特化是指对模板中的部分参数进行特化。偏特化允许我们针对特定的参数组合提供不同的定义。例如
templatetypename T, typename U
class Pair
{
public:T first;U second;
};templatetypename T
class PairT, T
{
public:T element;
};在上面的例子中我们定义了一个通用的模板类 Pair包含两个类型参数 T 和 U。然后我们使用偏特化对两个类型参数相同的情况进行了特化。这意味着当我们创建 Pairint, int 这样的实例时将使用偏特化的定义即 Pairint, int 类型将只有一个 int 类型的成员 element。
总之全特化是对完整的模板进行特化将所有参数都替换为具体的类型或值而偏特化是对模板中的部分参数进行特化允许我们为特定的参数组合提供不同的定义。这两种特化形式使得C中的模板更加灵活和强大。
通过模板偏特化获取类型所占字节数
偏特化加可变参数
#pragma once
#include iostream
using namespace std;//泛化
templateclass T,class ... ParamTypes
class Flen
{
public:enum{Number FlenT::Number FlenParamTypes...::Number//得到最终类型大小};
};//偏特化
templateclass Last
class FlenLast
{
public:enum{Number sizeof(Last)};
};#include iostream
#includeadvanced.hint main()
{Flenint, float, double, intlen;//输出结果位20 (44844)cout len.Number endl;return 0;
}通过模板偏特化和宏获取类型所占字节数
…ParamTypes和ParamTypes…的区别
ParamTypes…ParamTypes…将被展开为一系列类型参数并传递给Flen模板的实例化 … ParamTypes…是展开模板参数包的语法而不是参数包本身的一部分。class … ParamTypes是用于展开模板参数包ParamTypes的语法
SpawnIndex3, int, float, double在上面的代码中3 是一个非类型模板参数int, float, double 是类型模板参数。在 SpawnIndex 的定义中 …ParamTypes 将类型模板参数完整地展开将 int, float, double 分别作为一个参数展开。 而 ParamTypes … 将 int, float, double 作为一个整体展开。 advanced.h #pragma once
#include iostream
using namespace std;//泛化
templateclass T,class ... ParamTypes
class Flen
{
public:enum{Number FlenT::Number FlenParamTypes...::Number//得到最终类型大小};
};//偏特化
templateclass Last
class FlenLast
{
public:enum{Number sizeof(Last)};
};#define A(Name, ...)Flen__VA_ARGS__Name;//通过__VA_ARGS__接收 学习.cpp #include iostream
#includeadvanced.hint main()
{Flenint, float, double, intlen;//输出结果位20 (44844)cout len.Number endl;A(len2, int, float, double, int, long long);//输出结果位28 (448448)cout len2.Number endl;return 0;
}通过继承实现模板展开
using
using单独使用相当于为类或结构体起别名
using Helloc SpawnIndex10::Type;给类Type起了别名Helloc advanced.h #pragma once
#include iostream
using namespace std;//定义
templateint ...
struct HelloIndex
{};//展开的中间值
templateint N,int ...ParamTypes//N代表最大的...ParamTypes代表数字
struct SpawnIndex :SpawnIndexN - 1, N - 1, ParamTypes ...
{};//终止如果没有此会无限循环
templateint ... ParamTypes
struct SpawnIndex0, ParamTypes ...
{typedef HelloIndexParamTypes...Type;
};学习.cpp #include iostream
#includeadvanced.hint main()
{using Helloc SpawnIndex10::Type;//展开一个10同时为类Type起了一个别名Helloc//using单独使用相当于给类或结构体起别名//查看展开cout typeid(Helloc).name() endl;//输出结果struct HelloIndex0,1,2,3,4,5,6,7,8,9SpawnIndex3::Type;//SpawnIndex3::Type;的展开过程// //匹配到struct SpawnIndex :SpawnIndexN - 1, N - 1, ParamTypes ...进行运算//struct SpawnIndex :SpawnIndex 2, 2// //struct SpawnIndex 2, 2 :SpawnIndex 1, 1, 2// N ParamTypes N N ParamTypes //左边是templateint N,int ...ParamTypes的形式右边是SpawnIndexN - 1, N - 1, ParamTypes ...// //struct SpawnIndex 1, 1, 2 :SpawnIndex 0, 0, 1, 2//因为N值为0了展开到这一步会终止之后匹配struct SpawnIndex0, ParamTypes ...此模板进行下面步骤// //typedef HelloIndex 0, 1, 2Type;return 0;
}ue4源码的模板综合了很多如可变参数、特化、非特化
通过using循环命名的方式来展开可变参数 advanced.h #pragma once
#include iostream
using namespace std;//定义
templateint ...
struct HelloIndex
{};//通过using展开的中间值
templateint N, int ...ParamTypes
struct SpawnIndex
{using Type typename SpawnIndexN - 1,N - 1, ParamTypes...::Type;//编译器先发现Type之后发现后面代码之后一层层递归递归过程中参数会改变
};//循环终止
templateint ... ParamTypes
struct SpawnIndex0, ParamTypes ...//最后在参数为0时运行最后模板
{typedef HelloIndexParamTypes...Type;
};学习.cpp #include iostream
#includeadvanced.hint main()
{using Helloc SpawnIndex10::Type;//查看展开cout typeid(Helloc).name() endl;//输出结果struct HelloIndex0,1,2,3,4,5,6,7,8,9return 0;
}
typename 是一个关键字用于在模板编程中指示一个依赖类型。它通常用于声明模板中的类型参数用于告知编译器某个名字代表一个类型
问题为什么又两个N-1 在模板参数SpawnIndexN, int ...ParamTypes中N - 1在每次递归调用时作为新的模板参数传递给SpawnIndex而N - 1, N - 1则是作为递归调用的模板参数。这两个参数的作用如下
首先在每次递归调用时N - 1作为新的模板参数传递给SpawnIndexN - 1, N - 1, ParamTypes...::Type它用于更新N的值实现递减。这样在每次递归时N的值都会减小直到最后递归到SpawnIndex0, ParamTypes...从而触发递归终止的模板。
其次在递归调用中N - 1, N - 1作为ParamTypes的一部分被传递给递归调用的模板参数列表。这样新的模板参数列表中会包含N - 1, N - 1, ParamTypes...并被传递给下一次递归调用。这样每次递归调用时ParamTypes列表都会逐渐增长记录了调用的历史信息。
综上所述N - 1主要用于控制递归调用的次数而N - 1, N - 1在递归调用中记录了每次递归的历史信息。