使用nas建设网站,浠水网站建设,企业网站域名注册,营销推广有哪些形式开门见山
以下代码可展开模板参数包和展开函数参数包。
// lambda折叠表达式(需C17)
#include iostream
using namespace std;// 1.展开模板参数包
templatetypename ...T
void Func1()
{([]() {cout typeid(T).name() endl;}(), ...);// …开门见山
以下代码可展开模板参数包和展开函数参数包。
// lambda折叠表达式(需C17)
#include iostream
using namespace std;// 1.展开模板参数包
templatetypename ...T
void Func1()
{([]() {cout typeid(T).name() endl;}(), ...);// 折叠表达式
}
// 2.展开函数参数包
templatetypename ...T
void Func2(T... args)
{([args]() {cout args endl;}(), ...);// 折叠表达式
}
void main(){cout 开门见山 endl;cout 1.展开模板参数包 endl;Func1char, bool, int, char, const char*();cout endl;cout 2.展开函数参数包 endl;Func2(c, true, 2, h, CSDN越来越好。。。);
}文章目录开门见山前言提前声明遇到的问题一步一步理解过程1.1 模板推断类型1.2 参数包转发、递归解函数包1.3 不用递归解包-外部函数-折叠表达式1.4 不用递归解包-lambda函数-折叠表达式1.5 lambda折叠表达式解开模板参数包1.6 回归组件代码前言
提前声明 关于 我菜鸟一枚文中的术语、代码、文字若有错误欢迎指正 阅读本文需要了解的知识 模板、模板参数包、函数参数包、参数包转发、扩展参数包、折叠表达式、lambda函数。 本文目的 是记录自己遇到的C语法问题如何运用所学知识慢慢理解的过程不属于学习语法文章。 相关不理解知识点建议百度。
遇到的问题 需求说明 在Unity的游戏引擎中CtrlD复制一个物体新物体应该具有旧物体的各个组件。 组件列表有TransformComponent、SpriteRendererComponent、CircleRendererComponent。 如果要复制这三个组件给新物体假设Unity内部实现代码如下 templatetypename Component
static void CopyComponentIfExists(Entity dst, Entity src) {if (src.HasComponentComponent()) {// 新物体添加旧物体组件dst.AddOrReplaceComponentComponent(src.GetComponentComponent());}
}
void Scene::DuplicateEntity(Entity entity)
{// 1.创建旧实体同名的新实体std::string name entity.GetName();Entity newEntity CreateEntity(name);// 2.复制组件CopyComponentIfExistsTransformComponent(newEntity, entity);CopyComponentIfExistsSpriteRendererComponent(newEntity, entity);CopyComponentIfExistsCircleRendererComponent(newEntity, entity);
} 简化代码 若组件列表有20个那么CopyComponentIfExists这行代码需要20个显然代码会冗余应使用模板来简化此代码代码如下 templatetypename... Component
struct ComponentGroup {
};
using AllComponents ComponentGroupTransformComponent, SpriteRendererComponent,CircleRendererComponent;templatetypename... Component
static void CopyComponentIfExists(Entity dst, Entity src) {([]() {if (src.HasComponentComponent()) {// 新物体添加旧物体组件dst.AddOrReplaceComponentComponent(src.GetComponentComponent());}}(), ...);
}
templatetypename... Component
static void CopyComponentIfExists(ComponentGroupComponent..., Entity dst, Entity src) {CopyComponentIfExistsComponent...(dst, src);
}
void Scene::DuplicateEntity(Entity entity)
{// 1.创建旧实体同名的新实体std::string name entity.GetName();Entity newEntity CreateEntity(name);// 2.复制组件CopyComponentIfExists(AllComponents{}, newEntity, entity);//CopyComponentIfExistsTransformComponent(newEntity, entity);//CopyComponentIfExistsSpriteRendererComponent(newEntity, entity);//CopyComponentIfExistsCircleRendererComponent(newEntity, entity);
}模板代码完成新物体拷贝旧物体组件的任务。 假设有20个组件类型只要在AllComponents写上这20个组件再调用CopyComponentIfExists(AllComponents{}, newEntity, entity);就不用像之前写20行代码。 但是缺点也产生了就是代码变得很难理解了。 简化核心代码 tips这里被下面过程称为 组件代码 我看到上一小点的代码不知模板如何运作的于是写下以下简洁版代码只要理解了以下代码等同于理解上一小点的代码 #include iostream
using namespace std;struct TransformComponent {TransformComponent() { cout TransformComponent() endl; }
};
struct SpriteRendererComponent {SpriteRendererComponent() { cout SpriteRendererComponent() endl; }
};
struct CircleRendererComponent {CircleRendererComponent() { cout CircleRendererComponent() endl; }
};templatetypename... Component
struct ComponentGroup {ComponentGroup() { cout ComponentGroup() endl; }
};
using AllComponents ComponentGroupTransformComponent, SpriteRendererComponent,CircleRendererComponent;// 为复制实体的辅助方法
templatetypename... Component
static void CopyComponentIfExists() {([]() {cout typeid(Component).name() endl;}(), ...);
}
templatetypename... Component
static void CopyComponentIfExists(ComponentGroupComponent...) {CopyComponentIfExistsComponent...();
}
void main() {CopyComponentIfExists(AllComponents{});
}这简化核心版的代码别称组件代码最重要的就是理解如何展开模板参数包 由于在网上搜索相关模板参数知识点都是讲如何展开函数参数包的没有讲如何展开模板参数包也许我自己菜没有搜到所以无奈在自己花了一下午的时间自己慢慢试出来了编码理解过程如下。
一步一步理解过程
1.1 模板推断类型 参考例子1 #include iostream
#include string
using namespace std;templatetypename T
static void Func1(T t) {T t2 8;cout t t2 endl;
}
templatetypename T
static void Func2() {T t 7;cout t endl;
}
void main() {Func1int(3);Func1(4);// 这就是省略了声明模板类型由参数4推断Func1的模板T类型为intFunc2int();
}所以可以理解以下代码 templatetypename... Component
struct ComponentGroup {ComponentGroup() { cout ComponentGroup() endl; }
};
using AllComponents ComponentGroupTransformComponent,SpriteRendererComponent,CircleRendererComponent;templatetypename... Component
static void CopyComponentIfExists(ComponentGroupComponent...) {// 传给CopyComponentIfExists的模板参数包为当前函数参数包推断出来的模板参数包CopyComponentIfExistsComponent...();
}
void main() {// 传入AllComponents{}代表传入实参CopyComponentIfExists的模板类型从实参推断出来CopyComponentIfExists(AllComponents{});
}在CopyComponentIfExists函数内 ComponentGroup是带有模板参数包的struct ComponentGroupComponent… Component…模板参数包由函数参数包AllComponents{}推断出来像上面例子1的Func1(4); 由于AllComponents ComponentGroupTransformComponent,SpriteRendererComponent,CircleRendererComponent 传入的函数参数包AllComponents{} 则能推断出模板参数包为 Component… TransformComponent, SpriteRendererComponent,CircleRendererComponent 得到了Component…模板参数包后再当做显示的模板传给下个函数 代码CopyComponentIfExistsComponent…(); 相当于 CopyComponentIfExistsTransformComponent, SpriteRendererComponent,CircleRendererComponent();
1.2 参数包转发、递归解函数包 此小节为理解 参数包转发解函数包概念 则给出以下代码 例子2显示指定模板参数包类型、并传入函数参数包(与上有点不同为理解解包概念)、并递归解函数包 #include iostream
using namespace std;// 2.递归解函数包
void Func2() { cout Func2()因为解包完了无参数就调用此函数代表递归解包结束 endl; }// 递归终止函数templatetypename T, typename ...TT
void Func2(T val, TT... args) // 函数参数包的第一个赋给第一个参数剩下的都给参数包args
{cout val -- typeid(val).name() endl;// 打印获取当前参数包的第一个参数值和类型// 继续解包,将函数参数包传给本函数递归不指定模板参数包类型由函数参数包推断出来Func2(args...);
}
// 1.参数包转发
templatetypename... T
void Func1(T... args) {/*传给Func2函数的模板参数包为当前函数参数包推断出来的模板参数包并将多个实参传入与CopyComponentIfExistsComponent...();不同这里有传递实参*///Func2T...(args...); // 转发模板参数包函数参数包Func2int, int, char, char const*(args...);// 与上一段代码调用一样只不过显示指定模板参数包类型
}
void main() {cout 参数包转发、递归解包 endl;Func1(2, 3, c, 12312);
}1.3 不用递归解包-外部函数-折叠表达式 引入 由1.2的例子解包知道了解包概念和流程但是为靠近一开始的组件代码不使用递归而实现的解包代码如下 #include iostream
using namespace std;// 2.不用递归解包
template class T
void Func2(T val)
{cout val -- typeid(val).name() endl;
}
templatetypename ...T
void Func2(T... args)
{/* 重点在这(func(args), ...);意思是逐个展开args函数参数包并将解开的一个参数传入Func2有多少个参数就有多少个Func2的调用。可以理解展开的语句为Func2(2), Func2(3), Func2(c), Func2(12312);*/(Func2(args), ...);// 折叠表达式解包
}
// 1.参数包转发
templatetypename... T
void Func1(T... args) {/*传给Func2函数的模板参数包为当前函数参数包推断出来的模板参数包并将多个实参传入与CopyComponentIfExistsComponent...();不同这里有传递函数参数包*/Func2T...(args...); //Func2int, int, char, char const*(args...);// 与上一段代码调用一样
}
void main() {cout 不用递归解包-外部函数 endl;// 相当于Func2(2, 3, c, 12312);但为了与前一致讲述参数包转发所以还是Func1Func1(2, 3, c, 12312);
}1.4 不用递归解包-lambda函数-折叠表达式
由1.3例子的重点那段注释Func2(args)可以改写成lambda匿名函数
#include iostream
using namespace std;// 2.不用递归解包-并用lamda
templatetypename ...T
void Func2(T... args)
{/*重点在这([](){}(), ...);意思是逐个展开args函数参数包并将解开的一个参数被lambda捕获有多少个参数就有多少个lambda的调用。可以理解展开的语句为args 2; []() {cout args -- typeid(args).name() endl; }(); args 3; []() {cout args -- typeid(args).name() endl; }(); args c; []() {cout args -- typeid(args).name() endl; }(); args 12312; []() {cout args -- typeid(args).name() endl; }();实际上args函数参数包被展开的新变量名为:args_0、args_1、args_2、args_3*/// 隐式引用捕获的是解开args函数参数包得到一个参数赋给args的变量([]() {cout args -- typeid(args).name() endl;}(), ...);// 折叠表达式解包
}
// 1.参数包转发
templatetypename... T
void Func1(T... args) {Func2T...(args...);
}
void main() {cout 不用递归解包-lambda endl;Func1(2, 3, c, 12312);
}1.5 lambda折叠表达式解开模板参数包
由1.4的例子发现与原组件代码很接近了但是原组件代码并没有函数参数包传递只有推断出来的模板参数包传递。
于是问题再于是否能像1.4代码用lamda解函数参数包那样解开模板参数包呢答案是肯定的如下
#include iostream
using namespace std;// 2.用lamda解开模板参数包
templatetypename ...T
void Func2()
{// 隐式引用捕获的是解开模型参数包得到一个类型赋给T的变量// 但是不写也行1.4节要写也许args是参数在函数体内而这里T是类型且在函数体外所以不用([]() {cout typeid(T).name() endl;}(), ...);// 折叠表达式
}
// 1.模板参数包转发
templatetypename... T
void Func1(T... args) {// 模板参数包的由参数包推断出来// T... int, int, char, const char*转发模板参数包Func2T...();
}
void main() {cout 类似组件(代码)-模板参数包转发-lambda解包 endl;Func1(2, 3, c, 12312);
}1.6 回归组件代码
由以上的步骤不难理解原本的组件代码意思和流程了
传入AllComponents{}代表传入实参第一个函数的模板参数包由函数参数包推断出来第一个函数推断出来的模板参数包转发传递给第二个函数第二个函数接收到传过来的模板参数包用折叠表达式解开模板参数包并用lambda输出
#include iostream
using namespace std;struct TransformComponent {TransformComponent() { cout TransformComponent() endl; }
};
struct SpriteRendererComponent {SpriteRendererComponent() { cout SpriteRendererComponent() endl; }
};
struct CircleRendererComponent {CircleRendererComponent() { cout CircleRendererComponent() endl; }
};templatetypename... Component
struct ComponentGroup {ComponentGroup() { cout ComponentGroup() endl; }
};
using AllComponents ComponentGroupTransformComponent, SpriteRendererComponent,CircleRendererComponent;// 4.接收到传过来的模板参数包
// Component... TransformComponent, SpriteRendererComponent,CircleRendererComponent
templatetypename... Component
static void CopyComponentIfExists() {// 5.解开模板参数包并用lambda输出([]() {cout typeid(Component).name() endl;}(), ...);// (, ...)折叠表达式解包
}
// 2.模板参数包由函数参数包推断出来
templatetypename... Component
static void CopyComponentIfExists(ComponentGroupComponent...) {// 3.推断出来的模板参数包转发传递CopyComponentIfExistsComponent...();// Component... TransformComponent, SpriteRendererComponent,CircleRendererComponent
}
void main() {cout 1.6 回归组件代码endl;CopyComponentIfExists(AllComponents{});// 1.传入AllComponents{}代表传入实参
/*
由于AllComponents{} ComponentGroupTransformComponent, SpriteRendererComponent,CircleRendererComponent()
所以CopyComponentIfExists(AllComponents{});等价CopyComponentIfExists(ComponentGroupTransformComponent, SpriteRendererComponent, CircleRendererComponent());
*/
}