首页后端开发其他后端知识C++元编程学习要了解哪些,元编程的概念是什么

C++元编程学习要了解哪些,元编程的概念是什么

时间2024-03-26 00:20:03发布访客分类其他后端知识浏览734
导读:这篇文章主要介绍了title,小编觉得挺不错的,现在分享给大家,也给大家做个参考,希望大家通过这篇文章可以有所收获。 模板 由于模板元编程需要以面向对象为基础,所以如有疑问之处可以先补充一点C++面向对象的知识: C++面向对象这一篇就...
这篇文章主要介绍了title,小编觉得挺不错的,现在分享给大家,也给大家做个参考,希望大家通过这篇文章可以有所收获。

模板

由于模板元编程需要以面向对象为基础,所以如有疑问之处可以先补充一点C++面向对象的知识:

C++面向对象这一篇就够了

泛型初步

由于C++是静态强类型语言,所以变量一经创建,则类型不得更改。如果我们希望创建一种应用广泛地复数类型,那么相应地需要基于intfloatdouble这些基础类型逐一创建,十分麻烦。泛型编程便是为了简化这一过程而生。

能够容纳不同数据类型作为成员的类被成为模板类,其基本方法为在类声明的上面加上一行模板声明代码

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
vue是前端css框架吗,VUE框架原理是什么 用PHP怎样编写一个计算加减乘除余的计算器?

游客 回复需填写必要信息