iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++元编程语言初步入门详解
  • 109
分享到

C++元编程语言初步入门详解

2024-04-02 19:04:59 109人浏览 独家记忆
摘要

目录模板泛型初步函数模板友元模板参数元编程的基本概念可变参数模板模板 由于模板元编程需要以面向对象为基础,所以如有疑问之处可以先补充一点c++面向对象的知识: C++面向对象这一篇就

模板

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

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

泛型初步

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

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

template<typename T>,下一行为class myClass,其调用过程为myClass<T> m。

列举案例如下


#include<iOStream>
using namespace std;
template<typename 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(){
    Abstract<float> fTemp{1,2};//C类型为float
    fTemp.multi(fTemp);
    fTemp.printVal();
    system("pause");
    return 0;
}

函数模板

当然,上述multi并不能实现两个不同类型的Abstract之间的相乘,所以可以将multi函数改为


    template<typename T>
    Abstract<C>& multi(Abstract<T> val){
        C temp = real*val.real - im*val.im;
        im = real*val.real + im*val.im;
        real = temp;
        return *this;
    }

这样就能够实现如下功能。


int main(){
    Abstract<float> fTemp{1,2};
    Abstract<int> iTemp{1,2};
    fTemp.multi(iTemp);
    fTemp.printVal();
    getReal(fTemp);
    system("pause");
    return 0;
}

友元

模板类具备一部分普通类的性质,比如struct和class的区别,public、protected、private的性质,以及友元等。模板的声明特性也可以应用在函数中,例如


#include<iostream>
using namespace std;
template<typename 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;
    }
    template<typename T> friend void getReal(Abstract<T> num);  //声明友元
};
template<typename C>
void getReal(Abstract<C> num){
    cout<<num.real<<endl;
}
int main(){
    Abstract<float> fTemp{1,2};
    fTemp.multi(fTemp);
    fTemp.printVal();
    getReal(fTemp);
    system("pause");
    return 0;
}

需要注意的一点是,在模板类中声明友元,其前缀<typename T>中的类型标识不得与已有的类型标识重复,否则编译无法通过。

由于函数模板可以针对不同的数据类型进行求解操作,是对函数或者方法实例的抽象,所以又被称为算法

模板参数

如果将模板理解为一种类型声明的函数,那么模板也应该具备一些函数具备的功能。首先其模板参数中可以包含实际类型参数,例如


template<typename T, int max>
class Test{}

其调用时可以写为


Test<int,256> pixel;

模板同样支持默认参数,即可以实现如下形式


template<typename T=int, int max=256>
class Test{}
Test pixle;

除了数据类型、值之外,模板本身也可以作为模板参数,例如下面的形式是合法的。


template<typename T, template<typename> class C>
struct Test{
    C<T>* val;
    Test(C<T>* inVal){
        val = inVal;
    }
};
int main(){
    Abstract<int> fTemp{1,2};
    Test<int,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相似


template<typename T>
struct Test{
    using type = T;
}

元编程的基本概念

元编程是泛型编程的一个超集,两者的本质均是针对不同数据类型的算法,后者则更关注传入参数的广泛性。如果将元编程分为四个层次

  • 无计算
  • 运算符连接的运算
  • 编译时具备选择等非递归计算
  • 编译时具备递归运算

那么泛型编程可以作为第一类元编程,或者说更加关注的是参数的传入传出过程,而元编程则更关注不同数据类型的选择过程。

例如,我们可以实现一个最多包含三个元素的元组Tuple,其思路为,三元元素可以看成是一个二元元组与一个参数的组合;二元元组可以看成是一元元组与参数的组合;一元元组则是一个基本数据类型的变量。在这个元组的实现过程中,除了赋值过程实现泛型之外,也需要判断当前所实现的元组元素个数,如果其初始化参量为3个时,需要递归式地创建变量,直到赋值参数为1个。则其实现如下


class Nil{};
//主模板
template<typename T1=Nil, typename T2=Nil, typename T3=Nil>
struct Tuple : Tuple<T2,T3>{
    T1 x;
    using Base = Tuple<T2,T3>;      //三元元组以二元元组为基础
    //返回值为Tuple<T2,T3>指针类型的base()函数
    //static_cast将this转化为Base*类型
    Base* base(){return static_cast<Base*>(this);}
    const Base* base() const {return static_cast<const Base*>(this);}
    //构造函数继承二元元组,在构造本类中x的同时,构造基类Tuple<T2,T3>
    Tuple(const T1& t1, const T2& t2, const T3& t3)
        :Base{t2,t3},x{t1}{}
};
template<typename T1>
struct Tuple<T1>{
    T1 x;
};
template<typename T1, typename T2>
struct Tuple<T1,T2> : Tuple<T2>{
    T1 x;
    using Base = Tuple<T2>;
    Base* base(){return static_cast<const Base*>(this);}
    const Base* base() const {return static_cast<const Base*>(this);}
    Tuple(const T1& t1,const T2& t2):Base{t2}, x{t1}{}
};
template<typename T1, typename T2, typename T3>
void print_elements(ostream& os, const Tuple<T1,T2,T3>& t){
    os<<t.x<<",";
    print_elements(os,*t.base());
}
template<typename T1, typename T2>
void print_elements(ostream& os, const Tuple<T1,T2>& t){
    os<<t.x<<",";
    print_elements(os,*t.base());
}
template<typename T1>
void print_elements(ostream& os, const Tuple<T1>& t){
    os<<t.x;
}
//运算符重载
template<typename T1, typename T2, typename T3>
ostream& operator<<(ostream& os, const Tuple<T1,T2,T3>& t){
    os<<"{";
    print_elements(os,t);
    os<<"}";
    return os;
}
int main(){
    Tuple<int,double,char> x{1,2.5,'a'};
    cout<<x<<endl;
    system("pause");
    return 0;
}

其输出结果为


PS E:\Code\cpp> g++ .\generic.cpp
PS E:\Code\cpp> .\a.exe
{1,2.5,a}

可变参数模板

上述实现过程非常繁琐,而且限制了元组中的元素个数,如果标准库中用上述的书写风格,那么标准库除了这个元组之外也写不了其他的东西了。好在C++模板提供了可变参数的功能,例如,我们可以先将打印模板函数写为


//typename... T 代表可变参数
template<typename T1, typename... T>
void print_elements(ostream& os, const Tuple<T1,T...>& t){
    os<<t.x<<",";
    print_elements(os,*t.base());
}
template<typename T1>
void print_elements(ostream& os, const Tuple<T1>& t){
    os<<t.x;
}
template<typename... T>
ostream& operator<<(ostream& os, const Tuple<T...>& 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也做相同的更改


template<typename T1, typename... T>
struct Tuple : Tuple<T...>{
    T1 x;
    using Base = Tuple<T...>;      //N+1元元组以N元元组为基
    Base* base(){return static_cast<Base*>(this);}
    const Base* base() const {return static_cast<const Base*>(this);}
    //注意T&...的书写格式
    Tuple(const T1& t1, const T&... t):Base{t...},x{t1}{}
};
template<typename T>
struct Tuple<T>{
    T x;
};

int main(){
    Tuple<string, double,int,char> tt("hello",1.5,1,'a');
    cout<<tt<<endl;
    system("pause");
    return 0;
}

其输出结果为


PS E:\Code\cpp> g++ .\generic.cpp
PS E:\Code\cpp> .\a.exe
{hello,1.5,1,a}

以上就是C++元编程语言初步入门详解的详细内容,更多关于C++元编程语言初步的资料请关注编程网其它相关文章!

--结束END--

本文标题: C++元编程语言初步入门详解

本文链接: https://www.lsjlt.com/news/155059.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++元编程语言初步入门详解
    目录模板泛型初步函数模板友元模板参数元编程的基本概念可变参数模板模板 由于模板元编程需要以面向对象为基础,所以如有疑问之处可以先补充一点C++面向对象的知识: C++面向对象这一篇就...
    99+
    2024-04-02
  • c# 异步编程入门
    目录一、什么算异步? 二、在编程中的异步 三、原始的异步编程模式之回调函数# 1、回调函数 一、什么算异步?   广义来讲,两个工作流能同时进行就算异步,例...
    99+
    2024-04-02
  • C语言入门篇--初识C语言及数据类型
    目录1.什么是C语言?2.第一个C程序&&知识点2.1头文件2.2main函数2.3函数调用2.4return0;3.数据类型3.1C语言数据类型3.2为什么有这么多...
    99+
    2024-04-02
  • C语言入门篇--初识结构体
    目录1.为什么要有结构体2.结构体的定义2.1结构体类型的定义2.2定义结构体普通变量及访问2.3定义结构体指针变量及访问1.为什么要有结构体 (1)之前int、char等类型描述的...
    99+
    2024-04-02
  • 初学者必看:Go语言中的自然语言处理和异步编程入门教程
    Go语言是一种受到越来越多开发者喜爱的编程语言,它的简洁性和高效性让很多人对它青睐有加。在这篇文章中,我们将会介绍Go语言中的自然语言处理和异步编程。 自然语言处理(NLP)是人工智能领域的一个重要分支,它涉及到文本处理、语音识别和机器翻译...
    99+
    2023-07-25
    教程 自然语言处理 异步编程
  • C语言文件操作的入门详解教程
    目录一.一些需要掌握的知识点1.文件名2.文件类型3.数据流4.文件缓冲区5.文件指针二.与文件操作相关的一些函数 1.文件的打开及关闭2.文件的顺序读写3.文件的随机读写...
    99+
    2024-04-02
  • Go语言初探:编译过程详解
    标题:Go语言初探:编译过程详解 Go语言是一种开源的编译型静态语言,由谷歌开发,旨在提升编程效率和简化工程管理。作为一种现代化的编程语言,它具有出色的并发支持和高效的垃圾回收机制,同...
    99+
    2024-04-02
  • 探索C语言:适合初学者的计算机编程入门指南
    C语言是一种计算机编程语言,由美国贝尔实验室于20世纪70年代早期开发。C语言以简洁、高效和可移植性而闻名,被广泛用于操作系统、嵌入式系统以及各种应用程序的开发。对于初学者来说,学习C...
    99+
    2024-02-24
    c语言 编程指南 初学者
  • C语言入门之基础知识详解
    目录一、思维导图二、环境搭建三、编码规范四、基本数据类型五、分支循环5.1 分支5.2 循环六、break与continue6.1 无限循环一、思维导图 内容不限于此思维导图 二、...
    99+
    2024-04-02
  • C语言入门篇--关键字static详解
    目录1.修饰局部变量1.1作用1.2举例(1)不加static(2)加static(3)静态局部变量的初始化只会进行一次2.修饰全局变量2.1作用2.2举例(1)不加static(2...
    99+
    2024-04-02
  • Python编程入门基础语法详解
    一、基本概念内置的变量类型:Python是有变量类型的,而且会强制检查变量类型。内置的变量类型有如下几种:浮点float_number = 2.3复数complex_number = 1 + 5j整型integer_number = 1li...
    99+
    2023-06-02
  • 汇编语言入门汇编指令及寄存器详解教程
    目录前言什么是汇编语言汇编语言产生的原因汇编与二进制的关系寄存器寄存器作用存取速度比较寄存器分类常用寄存器用途寄存器EAX、AX、AH、AL的关系汇编语言指令数据传送指令算术运算指令...
    99+
    2024-04-02
  • Go语言编程入门指南
    Go语言(Golang)是由Google开发的一种编程语言,它的设计简洁、高效,并且具有很强的并发特性,因此受到了许多开发者的青睐。本文将为您提供一份简单的Go语言编程入门指南,介绍基...
    99+
    2024-04-02
  • 详解C语言初阶基础
    目录1.什么是c语言2.初始化:3.变量和常量4.作用域与生命周期简单阐述:作用域:生命周期(存在与消失):作用域与生命周期的区别作用域:生命周期:5.    &...
    99+
    2024-04-02
  • C语言编程函数指针入门精讲教程
    目录一、指针引子二、使用步骤1.取函数地址2.创建函数指针3.通过函数指针调用函数的两种方法三、函数指针进阶总结一、指针引子 示例:我们常常接触的指针大多有如下几类: 整形指针-存放...
    99+
    2024-04-02
  • C语言数组快速入门详细讲解
    目录1.一维数组a.一维数组的创建b.一维数组的初始化c.一维数组的使用d.一维数组在内存中的存储2.二维数组a.二维数组的创建b.二维数组的初始化c.二维数组的使用d.二维数组在内...
    99+
    2024-04-02
  • C语言之初始if语句详解
    目录if语句有三种常见的使用方式总结if语句有三种常见的使用方式 1. if() //满足条件 .....//执行的功能 (不满足条件则不执行任何功能) 2. if() //满足条件...
    99+
    2024-04-02
  • C语言在linux下编程详解
    目录文件操作总结文件操作 #include <sys/unistd.h> //含有close函数 #include <fcntl.h> //含有op...
    99+
    2024-04-02
  • 详解C语言初阶之函数
    目录 1.main函数2.自定义函数2.1  函数的的封装和面向过程的思维3.函数的组成3.1函数的命名法3.2函数的返回值3.2.1void类型补充:3.3形参...
    99+
    2024-04-02
  • 详解C语言初阶之数组
    目录1.数组1.1数组的概念1.2数组的定义 a:完全初始化b:不完全初始化 c:给定元素个数d:不给定元素个数1.3数组的下标访问总结1.数组 1.1数组的概念 所谓数组...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作