IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 浅析decltype一些有趣(实用)的用法 -> 正文阅读

[C++知识库]浅析decltype一些有趣(实用)的用法

目录

一、透过表象,直探本质

1.decltype关键字该如何理解?

2.auto VS decltype

二、decltype的使用分析

1.“()”中放入的是变量

2.“()”中放入的是表达式

3.“()”中放入的是函数

三、decltype的方便之处(实战演示)

【程序结果】

参阅资料



一、透过表象,直探本质

1.decltype关键字该如何理解?

??????decltype用于推导类型是大家都知道,可真正面对decltype的各种写法时,又容易迷失在类型判断的困境中。以上面的两行代码为例,来说明问题:

decltype(10) a;            //好比书写int a;
decltype('Q') b = 'b';    //好比书写char b = 'b';

????????相信大家也发现了,上面两句这样写非常类似于变量的定义和初始化。那么,不论decltype后的“()”中写的多么复杂,最后decltype()返回的结果必定只是一个类型而已。理解了这条本质,下面的问题讨论起来就轻松一些啦。

2.auto VS decltype

????????说起类型推断,马上就会有读者说:auto不也可以进行类型推断吗? auto确实可以进行类型推断,且与decltype都是在编译期进行类型推断的,但它们两者也有着以下的区别:

  • auto定义变量时必须立即初始化,而decltype使用起来更为灵活一些,“()”中可以放很多不同的东西;
  • decltype进行类型推断时,并不会计算表达式的值;
  • const限定符、引用等属性有可能会被auto抛弃,但decltype一般则不会抛弃任何东西。

二、decltype的使用分析

1.“()”中放入的是变量

? ? ? ? 这种情形下的类型推断比较好理解,故简单举例说明存在const、引用时的情况,且使用起来感觉与auto的类型推断差不多。

const int i = 1;
const int& j = i;

//decltype并不会抛弃const、引用等属性
decltype(i) m1 = 5;   //m1的类型为const int
decltype(j) m2 = m1; //m2的类型为const int&

2.“()”中放入的是表达式

int i = 0;
int *pI = &i;
int &rI = i;

decltype(rI + 1) j;  //因rI + 1返回的是一个整型表达式结果, 故j的类型为int
decltype(pI) k;  //因pI是一个指针变量, 故k的类型为int*
decltype(*pI) k1; //k1的类型为int&

????????某些读者可能会对最后一条语句的推断结果感到意外,笔者在此想做一番细致分析:首先,*pI得到的是指针所指向的对象,且*pI能作为左值使用(赋值);其次,才涉及到decltype的一条规则,即若()中的表达式能作为左值使用,那么decltype返回的就是一个引用类型

? ? ? ? 同时还有一种写法也有类似的效果,decltype((变量))的结果也是一个引用,具体而言给变量套上一层括号后,就成为了表达式,而该表达式能作为左值使用。

3.“()”中放入的是函数

? ? ? ? 与前两种情况相比,该情形下的用法会显得不那么容易理解。还是以实例来进行说明,帮助各位读者理解decltype与函数碰撞时所隐藏的秘密。

【测试代码】

#include<iostream>
 
using namespace std;
 
int add(int a)
{
	return a;
}
  
int main()
{
	decltype(add) *T = add;	  //函数指针的初始化	
	decltype(&add) t = add;  //同上
    decltype(add) &t2 = add;//函数引用的初始化

    //lambada表达式也是一种可调用对象
    auto add2 = [](int a, int b) -> int  
    {
        return a + b;
    };

    decltype(add2) t1 = add2; //将t1绑定到实际的可调用对象上

	cout <<"add:" << T(2) << endl;
    cout <<"add:" << t(3) << endl;
    cout <<"add:" << t2(4) << endl;
    cout <<"add2:" << t1(3,4) << endl;
    

    return 0;
}

【程序结果】

?【结果分析】

????decltype(add)?*T?=?add;? “()”中放入的是函数名,decltype推断后的结果为函数类型int(int),其后紧跟着*修饰,则得到了一个函数指针类型的变量T,其指向函数实体add。?

????decltype(&add)?t?=?add;? “()”中放入的是函数地址,decltype推断后的结果直接就是函数指针类型int(*)(int),此时得到了一个函数指针t,其指向函数实体add。

????decltype(add)?&t2?=?add; 与加指针标识符*的情况类似,最后获得的是函数引用类型。

????decltype(add2)?t1?=?add2;? “()”中放入的是函数名,返回的是函数类型int(int, int),此时获得是一个具有函数类型int(int, int)的对象t1。

等等...,具有函数类型的对象?啥意思? 换句话说,此时获得的t1为一种可调用对象(函数对象或仿函数),所以在上面的演示中才利用lambda表达式生成了add2对象,以作为t1的值。

三、decltype的方便之处(实战演示)

? ? ? ? 看到这儿,可能依然有读者觉得还不过瘾,甚至还可能觉得前面演示的decltype看起来也没多大威力嘛,况且还有“坑”,用不好就完蛋。

????????C++新标准里的东西,让人惊叹的同时,又让人感觉到费解。虽然笔者有着经典C++的基础,但在学习C++11之后的内容时,也是同大多初学者一样喜忧参半。作为新标准内容之一的decltype,最大的妙用还是在泛型编程中来使用,其强大的类型推断功能可以很好地与模板参数的推导结合起来。

????????下面是一份在二叉查找树中插入结点的实际例子,演示了decltype在泛型编程中的妙用:

#include<iostream>
#include<vector>
#include<stack>

using namespace std;

template<typename E>
struct TreeNode  //树结点结构
{
    E data;
    TreeNode<E>* left;
    TreeNode<E>* right;

    TreeNode(E e) : data(e), left(nullptr), right(nullptr) {}
};

//E有可能是自定义的类类型,故我们需要传入一个自定义比较函数
//即Comparator是针对类型E定义的
template<typename E, typename Comparator>
class BST
{
private:
    TreeNode<E>* root;  //BST的树根结点
    int size;          //BST的大小
    Comparator cmp;   //自定义的比较函数

public:
    BST(Comparator cmp) : root(nullptr), size(0), cmp(cmp) {}   
 
    void add(E e)  //插入结点
    {  
        if(!root) root = new TreeNode<E>(e);
        else 
        {
            TreeNode<E>* cur = root;
            while(cur) 
            {
                if( cmp(e, cur->data) < 0 && !cur->left ) {
                    cur->left = new TreeNode<E>(e);
                    size++;
                    return;
                }
                else if ( cmp(e, cur->data) > 0 && !cur->right ){
                    cur->right = new TreeNode<E>(e);
                    size++;
                    return;
                }
                //若能走到此处证明cur->right或cur->left不为空
                if( cmp(e, cur->data) < 0 ) cur = cur->left;
                else if( cmp(e, cur->data) > 0 ) cur = cur->right;
            }
        }
    }

    vector<E> print() 
    {  //中序遍历
        if(root == nullptr) return {};
        vector<E> res;           //保存访问结果
        stack<TreeNode<E>*> st; //保存树结点

        TreeNode<E>* cur = root;  //工作的结点指针
        while( cur != nullptr || !st.empty() ) {
            //1.找到最左子结点
            while(cur) {
                st.push(cur);
                cur = cur->left;
            } 
            //2.若到达此处时没有经过1, 则证明此时弹出的是某子树的root结点
            TreeNode<E>* node = st.top();
            st.pop();
            res.emplace_back(node->data);

            cur = node->right;
        }

    return res;
    }
};

int main()
{
    auto cmp = [](const int& x, const int& y) -> int
    {
        return x - y;
    };

    BST<int, decltype(cmp)> bst(cmp); //妙用之处!

    bst.add(33);
    bst.add(22);
    bst.add(45);
    bst.add(9);
    bst.add(35);

    vector<int> vc = bst.print();  //中序遍历BST,返回一个有序的序列
    for(auto &x : vc) {
        cout << x << " ";
    }

    return 0;
}

【程序结果】

参阅资料

> C++ primer 第5版

> 狄泰软件学院C++深度解析教程

> C++ 新经典—王健伟

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-15 15:39:53  更:2021-11-15 15:40:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:39:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码