
C++泛型与模板
文章平均质量分 83
浅慕Antonio
分享编程知识
展开
-
【元编程】std::tuple的实现
这里,我们使用另一种方法实现std::tuple,使用的是作为成员变量递归展开的方式,称为递归组合展开。原创 2024-11-29 17:50:27 · 1144 阅读 · 0 评论 -
【元编程】老式typelist的实现
typelist//空的typelistpublic:为了后续方便,使用宏定义先预定义一些typelist//宏定义简短嵌套代码。原创 2024-11-29 14:19:24 · 904 阅读 · 0 评论 -
【元编程】typelist的实现
typelisttypelisttypelist这个概念比较系统的出现是在ModernCDesignModernCDesign一书中,关于typelisttypelisttypelist的解释,就是用来操作一大堆类型的CC++C容器,就像std::list一样能够为数值提供各自操作一样,不过这里操作的是类型,而不是数值。这里,基于C11C++11C11以上的标准实现typ。原创 2024-11-29 11:50:00 · 984 阅读 · 0 评论 -
【元编程】混合元编程
元编程还有一种功能,成为混合元编程。1程序员写出一段元编程代码2编译器根据这段代码编译出一段新代码,实现程序真正功能的是这段生成的新代码3编译器会对这段新代码进行编译,产生最终的可执行程序。也就是说,混合元编程可以看作是运行期间的C代码生成器。原创 2024-11-29 11:08:53 · 949 阅读 · 0 评论 -
【元编程】元函数
元编程的英文名字是MetaProgramming,也称为模板元编程TemplateMetaprogramming,可以理解为一种编程手法,用于实现一些比较特殊的功能。元编程一般与“递归”有着比较密切的联系,代表着元编程这种编程手法中大多情况都会使用到递归的编程技术。之前的,可以看看具体的实现。传统的函数都是在程序运行期间被调用和执行,而元函数是能够在程序编译期间被调用和执行(编译期间就能得到结果)。C11引入了constexpr。原创 2024-11-28 23:42:34 · 891 阅读 · 0 评论 -
【萃取技术】策略技术中的算法策略
在之前介绍了trait用于参数的方法。实际上,我们也可以为这个函数模板的算法策略提供一个接口,比如我们可以计算这个范围内的差值,或者找到这个范围内的最小值。因此,我们需要再次改造参数列表,提供一个策略模板的参数,用于指定算法策略。然后,我们再改造一下funcsum如果我们需要一个取最小值的算法策略呢?显然,我们需要重新实现一个(参考),然后特化出各自类型,比如intcharfloat等等。这里就实现int。原创 2024-11-28 22:03:53 · 983 阅读 · 0 评论 -
【萃取技术】将trait类用作模板参数
traittrait。原创 2024-11-28 21:22:49 · 858 阅读 · 0 评论 -
【萃取技术】实现std::is_class、std::is_base_of
类型的变量,只是这样的写法在语义上是通过的,如果不是类类型,在语义上无法通过,因此会调用优先级低的。我们知道,基类的前提是两个类型都应该是类类型,并且派生类可以向父类发生隐式地转换。现在我们可以使用成员函数重载的方式实现一下这个类模板。可用于派生类向基类转换,如果可以发生转换,那么将调用。标准中用于判断某个类型是否是另一个类父类的类模板。,并且这个类可以被一个成员变量指针指向。的重载,如果一个类不是联合类型。版本的成员函数,得到的返回值为。的写法,类内部不一定要有。这里,我们使用成员函数。原创 2024-11-28 14:51:52 · 942 阅读 · 0 评论 -
【萃取技术】用成员函数重载实现is_convertible
这个类模板主要是判断某个类型是否能隐式地转换为另一个类型,类模板内部存在一个变量。可以在语义上构造出一个对象(实际上不会直接构造出),如果这个对象可以从。运行结果如下,因为基类不能隐式转换为派生类,所以。可以正确的得到返回值类型了, 此时将调用返回值为。,反之派生类可以隐式转换为基类,所以。有使用过,感兴趣可以先看看。首先需要实现一个辅助类,然后让。标准库中提供的可变参类模板。否则,就会调用优先级最低的。我们继承这个辅助类中的。函数,得到一个返回值。原创 2024-11-28 14:14:34 · 611 阅读 · 0 评论 -
【萃取技术】使用SFINAE特性的信息萃取
我们通过成员函数重载的方式,由于可变参类型的函数优先级最低,因此我们可以让无法匹配的在最后,此时一定就是没有默认构造了。通过这个特性,我们可以萃取出许多有趣和有用的信息,这里我们主要介绍如何利用这个特性实现。来判断返回值类型是否与`true_type``一样,如果是,则。类型,实际上这里是一个临时对象,有默认构造函数生成。的方式,也可以直接利用重载的函数的返回值来实现。中讲解了相关的概念,这里不过多叙述。首先有两个类型,其中一个具有默认构造的。而有默认构造的类型一定可以调用。类型,另一个实现了构造函数的。原创 2024-11-27 22:09:11 · 591 阅读 · 0 评论 -
【萃取技术】std::is_void和std::is_same
用于判断两个类型是否相同,如果类型相同,则类模板内部的。以上,也能实现其变量模板。,用来判断某个类型是不是。标准库中有一个类模板。原创 2024-11-27 21:36:13 · 1082 阅读 · 0 评论 -
【萃取技术】萃取技术中的值萃取
我们补充类对AAA//对A类型的特化版本template//必须类内定义类外声明//类外声明注意这里不能再类内初始化,需要在类外初始化initValueinitValueinitValue或者在C17C++17C17之后,使用关键字,可以在类内初始化,如BBBclass B {public:int m_i;template最后,由于存在加法操作,我们需要重载一下。原创 2024-11-27 21:16:56 · 573 阅读 · 0 评论 -
【萃取技术】引用类型的移除和增加
C11标准库提供了一个类模板,如果传进来的模板参数类型是一个引用类型,如&&,则会把这个引用类型中的引用部分删除。原创 2024-11-27 18:50:07 · 903 阅读 · 0 评论 -
【萃取技术】萃取技术及固定萃取
萃取这个词的英文是trait,也可以翻译成,这里统一翻译为萃取。萃取技术通常用于对模板中的各种模板参数进行管理。这种技术往往是通过写一个类模板来体现,而这种类模板也被成为“trait类模板”。从表现上来说,trait类模板像一个中间件一样,夹在不同的代码之间,使得代码之间结合或调用变得更加灵活。这里介绍的萃取技术为固定萃取fixedtraits,即传入一种类型,萃取出另外一种类型,只要传入的类型固定了,那么得到的类型也就固定下来了,因此被称为固定萃取。原创 2024-11-27 17:26:15 · 1356 阅读 · 0 评论 -
【模板进阶】std::is_union、std::is_class、std::integral_constant
std::isunion是C11引入的类模板,用于判断一个类是否是一个联合union类型。这个类模板中有一个value成员,如果类型T是union类型,那么这个value的值为1,否则为0。由于这个模板的实现与编译器内部的支持有关,因此更详细的源码需要查阅相应的资料。这里展示一下基本的使用方法:调用测试函数,打印相应的类名和value其中,C17之后,有相应的变量模板isunionv。原创 2024-11-15 22:23:21 · 912 阅读 · 0 评论 -
【模板进阶】std::integer_sequence
std::integersequencestd::integersequence是C14引入的的类模板,主要用于生成一个整型数字序列的,如012345这样的序列。这里的T一般使用的是intunsignedint等类型。原创 2024-11-15 21:55:12 · 986 阅读 · 0 评论 -
【模板进阶】std::remove_all_extents
removeallextents是C11引入的类模板,它的功能是把一个数组的数组类型部分移除,只保留元素类型。原创 2024-11-13 16:11:04 · 755 阅读 · 0 评论 -
【模板进阶】综合范例
如果是自定义类型,并且具有默认构造,然后我们也能够通过decltypedecltypedecltype来推导//重载一下+运算符elem() {}//创建临时对象//重载运算符-//...中间省略具体实现return res;其中具体的实现内容与类的具体使用有关,这里只做最基本的演示。原创 2024-10-09 16:27:21 · 872 阅读 · 0 评论 -
【模板进阶】std::function
stdfunctionstd::function是C11C++11C11引入的一个可调用对象包装器,它可以通过指定模板参数,统一来处理各自可调用对象。lambadalambadalambada//全局函数std::cout原创 2024-10-09 20:57:37 · 704 阅读 · 0 评论 -
【模板进阶】std::conditional
C++11C++11C++11标准引入了std::conditionalstd::conditionalstd::conditional,这是一个类模板,用于表现一种编译期间的分支逻辑。它的实现代码比较简单,如下所示:可以发现,在它的模板中,如果第一个参数为falsefalsefalse,那么我们将会调用它的特化版本,其内部的typetypetype将被替换为第二个UUU类型。反之,将调用它的泛化版本,typetypetype也将会被替换为第一个TTT类型。下面是std::conditionalstd::原创 2024-10-09 19:52:06 · 850 阅读 · 0 评论 -
【模板进阶】std::true_type和std::false_type
std::true_typestd::true\_typestd::true_type和std::false_typestd::false\_typestd::false_type实际上是类型别名,经常被使用到。例如标准库有以下的代码:所以,它们实际上是同一个类型的两种特化版本的别名,可以看作是两个类型,也可以看作是一个类型。下面是std::true_typestd::true\_typestd::true_type和std::false_typestd::false\_typestd::false_ty原创 2024-10-07 00:42:26 · 1146 阅读 · 0 评论 -
【模板进阶】std::void_t
C++17C++17C++17引入了std::void_tstd::void\_tstd::void_t,它其实是一个别名模板,源码非常简单,大概如下所示:它实际上是一个别名模板,但有个特点,就是无论传入什么都会变成voidvoidvoid类型。通过它的这个特性,我们能够检测到应用SFINAESFINAESFINAE特性时出现的非法类型,也就是说,传入的类型必须是有效的类型,而不是非法类型。考虑以下的代码:这里我们的HasInnerTypeHasInnerTypeHasInnerType内部有一个类型原创 2024-10-07 00:16:00 · 1075 阅读 · 0 评论 -
【模板进阶】std::declval
std::declvalstd::declvalstd::declval 是C++11C++11C++11标准中出现的一个函数模板。这个函数模板设计的比较奇怪(没有实现,只有声明),因此无法被调用,通常是和decltyedecltyedecltye和sizeofsizeofsizeof等关键字一起使用,来进行类型推导等等。下面是declvaldeclvaldeclval的一般源码实现:这里的std::add_rvalue_reference_tstd::add\_rvalue\_reference\_ts原创 2024-09-23 22:14:11 · 654 阅读 · 0 评论 -
【模板进阶】类模板中可变参的特殊继承方式
对于可变参类模板的继承方式总结起来就两种,其他方式可以看做是这两种方式的排列组合。1(1)1形如templateArgstemplateArgs...的单继承2(2)2形如templateArgstemplateArgs...的多继承继承的时候可以对这两种类型进行排列组合,也可以指定增加其中一个类型,如charcharchar类型等。注意,templateArgs。原创 2024-09-22 12:37:55 · 783 阅读 · 0 评论 -
【模板进阶】std::enable_if
在介绍std::enableifSFINAESubstitutionFailureisnosanError,即“替换失败不是一个错误”。SFINAE可以看做是C语言的一种特性或模板设计中要遵循的一个重要原则,非常重要,务必要理解好。现在,我们通过一个小样例来了解一下SFINAE比如,这里我们写了一个函数模板,返回类型是T::sizetype。原创 2024-09-21 11:30:48 · 806 阅读 · 0 评论 -
【模板进阶】完美转发
1直接调用: 如从main函数中调用funcMiddle函数,这其实就叫作直接调用。2转发:从main主函数中调用funcMiddle函数,然后通过funcMiddle调用funcLast函数,这就叫转发。3完美转发:在转发(中转这些参数)的过程中,这些参数的某些类型信息回丢失(如参数的cosnt属性,引用()等),显然这种转发就是不完美的。但是如果这些参数的类型信息可以原封不动地从funcMiddle。原创 2024-09-20 13:15:12 · 1198 阅读 · 0 评论 -
【模板进阶】auto类型的常规推断
autoautoauto并不陌生,早在C98C++98C98就有autoautoauto关键字,但当时的autoautoauto也只是一个自动变量的说明符,基本上没什么用处。直到C11C++11C11autoautoauto才被赋予了全新的含义——用于变量变量的自动类型推导。换句话说,就是在声明变量的时候根据变量类型自动为此变量选择匹配的类型,不需要程序员显式地指定类型。原创 2024-09-20 09:47:56 · 842 阅读 · 0 评论 -
【模板进阶】类型参数的推断
1(1)1带有引用类型的形参传入后,引用类型会被忽略。2(2)2无论形参是否带有constconstconst限定,只有实参具有constconstconst限定,那么推导出来的形参tmprvtmprvtmprv就一定具有constconstconst限定通过上面的范例,总结一下编码技巧。&①&形参中的引用有两个作用:可以通过对形参的修改来修改实参﹔传递引用比传值效率更高。原创 2024-09-19 19:53:50 · 808 阅读 · 0 评论 -
【模板进阶】模板的万能引用
这里的abc被推导为什么类型?显然可见,为constint类型,上面不都写着呢!这里传入的10显然是转换为了int类型,那么Tintabcconstint,这是容易推导出来的。原创 2024-09-19 17:07:47 · 1036 阅读 · 0 评论 -
【模板代码的组织结构与模板的显式实例化和声明】模板代码的组织结构与模板的显式实例化和声明
之前对于模板,我们都是写在同一个cpp文件下,那如果我们将模板分开,单独开一个h和cpp来创建模板,会发生什么?首先,我们创建一个myclassh注意这里的代码是防止多次引用头文件然后我们创建一个myclasscpp文件,类外实现一下模板然后再主函数maincpp看上去没什么问题,编译器也没有报错,我们运行一下:maincppMYClassintMYClass因此,解决方法就是在myclassh。原创 2024-09-17 20:31:20 · 1367 阅读 · 0 评论 -
【模板的特殊继承关系】用参数化的方式表达成员函数的虚拟性
实际上,只要继承列表中存在一个类具有虚成员函数,那么就会发生多态,这根本上是因为不管是多继承还是单继承,只要存在虚函数的基类,那么在派生类就会存在虚函数指针,在运行时发生多态。类,具有虚成员函数,因此继承链的所有类都具有虚成员函数,因此当基类调用派生类函数的时候会发生多态,而。这里我们运用的混入技术:派生类继承基类的模板。变为虚函数,这就是所谓的“用参数化的方式表达成员函数的虚拟性”。类不具有虚成员函数,因此调用的是自身的函数。类提供一个带有虚函数的类,那么就可以让。可以发现,虚函数的存在体现的多态。原创 2024-09-17 19:57:32 · 1036 阅读 · 0 评论 -
【模板的特殊继承关系】混入
混入Mixins这个概念,是一种编程手法,用于描述类与类之间的一种关系,这种关系比较类似于多重继承,看起来更像颠倒过来的基础(基类基础派生类)。混入的实现手段是把传入的模板参数当做该类模板的父亲。原创 2024-09-14 14:14:08 · 1440 阅读 · 0 评论 -
【模板的特殊继承关系】 奇异的递归模板模式
奇异的递归模板模式 (Curiously Recurring Template Pattern)(Curiously \ Recurring \ Template \ Pattern)(Curiously Recurring Template Pattern)不是一种新技术,而是一种模板编程中使用的编程手法:把派生类作为基类的模板参数。下面是一个简单范例:这样的继承方式在模板与泛型编程中很常见。以下介绍一下基本的几个用法。一般情况下,我们可以通过std::static_caststd::stati原创 2024-09-13 13:30:27 · 1122 阅读 · 0 评论 -
【多态在模板中的应用】静态多态
我们知道,通过基类定义虚函数,派生类重写基类的虚函数,在基类绑定派生类时,调用同名虚函数时,可以发生多态,这样的多态称为动态多态。因为这样的多态需要再运行时才能确定调用的成员函数是哪一个,这里不过多介绍。我们用父类引用绑定子类对象(也可以用父类指针),这样我们在调用子类虚函数时就能发生多态。原创 2024-09-13 10:54:42 · 415 阅读 · 0 评论 -
【可变参数模板】可变参数类模板的特化
可以发现,我们这里的偏特化版本都是基于参数范围上的特化。可变参数模板不存在特化,只有偏特化。原创 2024-09-13 10:34:29 · 318 阅读 · 0 评论 -
【可变参模板】基类参数包的展开
指针和第一个继承的基类相同,并且继承之后派生类的大小为自己的大小与所有基类的大小之和。对于基类参数的展开,一般是通过在构造函数中递归展开的,与递归组合的展开方式类似。关于多继承的细节不是泛型与模板的重点,因此这里只需要了解一下即可。是一个支持多继承的语言,因此继承的类也可以是一个基类的参数包。作为基类参数包的标志。原创 2024-09-12 23:48:49 · 362 阅读 · 0 评论 -
【可变参模板】可变参类模板
可变参类模板也和可变参函数模板一样,允许模板定义含有0到多个(任意个)模板参数。可变参类模板参数包的展开方式有多种,以下介绍几种常见的方法。原创 2024-09-12 18:14:00 · 1101 阅读 · 0 评论 -
【可变参模板】折叠表达式
折叠表达式FoldExpressions是C17标准引入的,引入折叠表达式的主要目的是计算某个值(表达式的结果当然是一个值)。这个值的特殊在于:它与所有可变参有关,而不是与但单独某个可变参有关。由于可变参的展开比较繁琐,所以使用这得表达式,可以不展开参数而计算出可变参的结果。原创 2024-09-10 10:13:53 · 722 阅读 · 0 评论 -
【可变参模板】可变参函数模板
可变参模板的英文名叫VariadicTemplate,是C11引入的标准。可变参模板允许参数的数量不固定,可以有任意多个。floatfloat得到下面结果:1在templatetypename...T中我们需要在typename后面加入...,表示当前的参数是参数包(可变参)2在函数模板的形参中,我们传入的是T...args类型,其中T...表示可变参类型(一包类型),而这时args。原创 2024-09-08 23:09:51 · 1126 阅读 · 0 评论 -
【类模板中的友元】友元函数
这是一个特殊的语法,我们可以在类内直接定义(不是声明)一个友元类,然后再类外可以直接调用它。注意下面代码,我们需要传入一个同类型的变量Men3Men3Men3,然后使用它调用Men3Men3Men3//在类模板中直接定义友元类//直接在类内定义友元函数friend void func4(Men3& men) { //传入自身相同的类private:std::cout原创 2024-09-06 16:17:58 · 1194 阅读 · 0 评论