C++元编程学习要了解哪些,元编程的概念是什么
模板
由于模板元编程需要以面向对象为基础,所以如有疑问之处可以先补充一点C++面向对象的知识:
C++面向对象这一篇就够了
泛型初步
由于C++是静态强类型语言,所以变量一经创建,则类型不得更改。如果我们希望创建一种应用广泛地复数类型,那么相应地需要基于int、float、double这些基础类型逐一创建,十分麻烦。泛型编程便是为了简化这一过程而生。
能够容纳不同数据类型作为成员的类被成为模板类,其基本方法为在类声明的上面加上一行模板声明代码
templatetypename T> ,下一行为class myClass,其调用过程为myClassT> m。
列举案例如下
#includeiostream>
using namespace std;
templatetypename C>
struct Abstract{
C real;
//real为C类型
C im;
Abstract(C inReal, C inIm){
real = inReal;
im = inIm;
}
void printVal(){
cout"Abstract:"real"+"im"i"endl;
}
;
Abstract&
multi(Abstract val){
C temp = real*val.real - im*val.im;
im = real*val.real + im*val.im;
real = temp;
return *this;
}
;
}
;
int main(){
Abstractfloat>
fTemp{
1,2}
;
//C类型为float
fTemp.multi(fTemp);
fTemp.printVal();
system("pause");
return 0;
}
函数模板
当然,上述multi并不能实现两个不同类型的Abstract之间的相乘,所以可以将multi函数改为
templatetypename T>
AbstractC>
&
multi(AbstractT>
val){
C temp = real*val.real - im*val.im;
im = real*val.real + im*val.im;
real = temp;
return *this;
}
这样就能够实现如下功能。
int main(){
Abstractfloat>
fTemp{
1,2}
;
Abstractint>
iTemp{
1,2}
;
fTemp.multi(iTemp);
fTemp.printVal();
getReal(fTemp);
system("pause");
return 0;
}
友元
模板类具备一部分普通类的性质,比如struct和class的区别,public、protected、private的性质,以及友元等。模板的声明特性也可以应用在函数中,例如
#includeiostream>
using namespace std;
templatetypename C>
class Abstract{
C real;
C im;
public:
Abstract(C inReal, C inIm){
real = inReal;
im = inIm;
}
void printVal(){
cout"Abstract:"real"+"im"i"endl;
}
;
Abstract&
multi(Abstract val){
C temp = real*val.real - im*val.im;
im = real*val.real + im*val.im;
real = temp;
return *this;
}
templatetypename T>
friend void getReal(AbstractT>
num);
//声明友元
}
;
templatetypename C>
void getReal(AbstractC>
num){
coutnum.realendl;
}
int main(){
Abstractfloat>
fTemp{
1,2}
;
fTemp.multi(fTemp);
fTemp.printVal();
getReal(fTemp);
system("pause");
return 0;
}
需要注意的一点是,在模板类中声明友元,其前缀typename T>
中的类型标识不得与已有的类型标识重复,否则编译无法通过。
由于函数模板可以针对不同的数据类型进行求解操作,是对函数或者方法实例的抽象,所以又被称为算法。
模板参数
如果将模板理解为一种类型声明的函数,那么模板也应该具备一些函数具备的功能。首先其模板参数中可以包含实际类型参数,例如
templatetypename T, int max>
class Test{
}
其调用时可以写为
Testint,256>
pixel;
模板同样支持默认参数,即可以实现如下形式
templatetypename T=int, int max=256>
class Test{
}
Test pixle;
除了数据类型、值之外,模板本身也可以作为模板参数,例如下面的形式是合法的。
templatetypename T, templatetypename>
class C>
struct Test{
CT>
* val;
Test(CT>
* inVal){
val = inVal;
}
}
;
int main(){
Abstractint>
fTemp{
1,2}
;
Testint,Abstract>
test(&
fTemp);
test.val->
printVal();
system("pause");
return 0;
}
其结果为
PS E:\Code\cpp>
g++ .\generic.cpp
PS E:\Code\cpp>
.\a.exe
Abstract:1+2i
请按任意键继续. . .
需要注意的一点是,在模板类中定义的模板类,需要进行实例化,否则会出现错误,所以在Test中,以指针形式创建了模板类。
类型函数
以数据类型为输入或输出的函数即为类型函数,在C语言中,sizeof便是一种类型函数,其输入为数据类型,输出为数据类型所需要的内存空间。
在C++11中,using可以实现数据类型赋予的功能,其使用方法与typedef相似
templatetypename T>
struct Test{
using type = T;
}
元编程的基本概念
元编程是泛型编程的一个超集,两者的本质均是针对不同数据类型的算法,后者则更关注传入参数的广泛性。如果将元编程分为四个层次
- 无计算
- 运算符连接的运算
- 编译时具备选择等非递归计算
- 编译时具备递归运算
那么泛型编程可以作为第一类元编程,或者说更加关注的是参数的传入传出过程,而元编程则更关注不同数据类型的选择过程。
例如,我们可以实现一个最多包含三个元素的元组Tuple,其思路为,三元元素可以看成是一个二元元组与一个参数的组合;二元元组可以看成是一元元组与参数的组合;一元元组则是一个基本数据类型的变量。在这个元组的实现过程中,除了赋值过程实现泛型之外,也需要判断当前所实现的元组元素个数,如果其初始化参量为3个时,需要递归式地创建变量,直到赋值参数为1个。则其实现如下
class Nil{
}
;
//主模板
templatetypename T1=Nil, typename T2=Nil, typename T3=Nil>
struct Tuple : TupleT2,T3>
{
T1 x;
using Base = TupleT2,T3>
;
//三元元组以二元元组为基础
//返回值为TupleT2,T3>
指针类型的base()函数
//static_cast将this转化为Base*类型
Base* base(){
return static_castBase*>
(this);
}
const Base* base() const {
return static_castconst Base*>
(this);
}
//构造函数继承二元元组,在构造本类中x的同时,构造基类TupleT2,T3>
Tuple(const T1&
t1, const T2&
t2, const T3&
t3)
:Base{
t2,t3}
,x{
t1}
{
}
}
;
templatetypename T1>
struct TupleT1>
{
T1 x;
}
;
templatetypename T1, typename T2>
struct TupleT1,T2>
: TupleT2>
{
T1 x;
using Base = TupleT2>
;
Base* base(){
return static_castconst Base*>
(this);
}
const Base* base() const {
return static_castconst Base*>
(this);
}
Tuple(const T1&
t1,const T2&
t2):Base{
t2}
, x{
t1}
{
}
}
;
templatetypename T1, typename T2, typename T3>
void print_elements(ostream&
os, const TupleT1,T2,T3>
&
t){
ost.x",";
print_elements(os,*t.base());
}
templatetypename T1, typename T2>
void print_elements(ostream&
os, const TupleT1,T2>
&
t){
ost.x",";
print_elements(os,*t.base());
}
templatetypename T1>
void print_elements(ostream&
os, const TupleT1>
&
t){
ost.x;
}
//运算符重载
templatetypename T1, typename T2, typename T3>
ostream&
operator(ostream&
os, const TupleT1,T2,T3>
&
t){
os"{
";
print_elements(os,t);
os"}
";
return os;
}
int main(){
Tupleint,double,char>
x{
1,2.5,'a'}
;
coutxendl;
system("pause");
return 0;
}
其输出结果为
PS E:\Code\cpp>
g++ .\generic.cpp
PS E:\Code\cpp>
.\a.exe
{
1,2.5,a}
可变参数模板
上述实现过程非常繁琐,而且限制了元组中的元素个数,如果标准库中用上述的书写风格,那么标准库除了这个元组之外也写不了其他的东西了。好在C++模板提供了可变参数的功能,例如,我们可以先将打印模板函数写为
//typename... T 代表可变参数
templatetypename T1, typename... T>
void print_elements(ostream&
os, const TupleT1,T...>
&
t){
ost.x",";
print_elements(os,*t.base());
}
templatetypename T1>
void print_elements(ostream&
os, const TupleT1>
&
t){
ost.x;
}
templatetypename... T>
ostream&
operator(ostream&
os, const TupleT...>
&
t){
os"{
";
print_elements(os,t);
os"}
";
return os;
}
其输出结果为
PS E:\Code\cpp>
g++ .\generic.cpp
PS E:\Code\cpp>
.\a.exe
{
1,2.5,a}
请按任意键继续. . .
然后将Tuple也做相同的更改
templatetypename T1, typename... T>
struct Tuple : TupleT...>
{
T1 x;
using Base = TupleT...>
;
//N+1元元组以N元元组为基
Base* base(){
return static_castBase*>
(this);
}
const Base* base() const {
return static_castconst Base*>
(this);
}
//注意T&
...的书写格式
Tuple(const T1&
t1, const T&
... t):Base{
t...}
,x{
t1}
{
}
}
;
templatetypename T>
struct TupleT>
{
T x;
}
;
/*
print模板
*/
int main(){
Tuplestring, double,int,char>
tt("hello",1.5,1,'a');
coutttendl;
system("pause");
return 0;
}
其输出结果为
PS E:\Code\cpp>
g++ .\generic.cpp
PS E:\Code\cpp>
.\a.exe
{
hello,1.5,1,a}
通过以上内容的阐述,相信大家对“C++元编程学习要了解哪些,元编程的概念是什么”已经有了进一步的了解,更多相关的问题,欢迎关注网络或到官网咨询客服。
声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!
若转载请注明出处: C++元编程学习要了解哪些,元编程的概念是什么
本文地址: https://pptw.com/jishu/653135.html
