首页 > 其他分享 >自动类型推导

自动类型推导

时间:2023-12-04 17:16:08浏览次数:28  
标签:const 推导 int auto 自动 类型 decltype

文章参考:爱编程的大丙 (subingwen.cn)

1. auto

在C++11之前,auto和static相对应用于表示变量是自动存储的,但是非static局部变量默认都是自动存储的,auto因此显得额外鸡肋。C++11中对auto进行了扩展,使他能够自动推导变量的实际类型。

1.1 推导规则

C++中auto并不是一种数据类型,而是一种用于声明类型的占位符。在使用auto时,必须对变量进行初始化,这样编译器才能推导出其实际数据类型,从而在编译时将auto替换为真正的数据类型。

auto简单使用:

auto a = 1;
auto b = 3.14;
auto c = 'a';
// auto d;		这里会报错,因为d没有经过初始化,无法使用auto

与指针、引用结合:

当auto和指针、引用结合时,可以带上const、volatile关键字,其推导规则如下:

  • 当变量是指针或引用类型时,推到结果才会带上const、volatile关键字。否则将会省略。

实例如下:

int temp = 1;
auto *a = &temp;
auto b = &temp;
auto &c = temp;
auto d = temp;
  • a类型为int *,因此auto的推导结果为int
  • b类型为int *,因此auto的推导结果为int *
  • c类型为int &,因此auto的推导结果为int
  • d类型为int,因此auto的推导结果为int

当带上const关键字时:

int tmp = 250;
const auto a = tmp;
auto b = a;
const auto &c = tmp;
auto &d = c;
  • a类型为const int,因此auto的推导结果为 int
  • b类型为int,因为b并没有声明为指针或是引用类型,因此const关键字被删去,auto的推导结果为 int
  • c类型为const int&,因此auto的推导结果为 int
  • d类型为const int&,d被声明为引用类型,const关键字得以保留,因此auto的推导结果为 int

1.2 auto限制

在一些场合中,auto关键字无法使用。

  • 不能作为函数参数使用。因为只有在函数调用时才会给到函数实参(程序运行时),而auto要求必须为变量初始化(编译时)。

  • 不能用于类的非静态成员初始化:

    class Test{
    private:
        // auto int a = 0;		编译报错。
        // static auto int b = 0;	编译报错,类的静态非常量成员必须在类外进行初始化
        const static auto int c = 0;	// 编译通过
    }
    
  • 不能使用auto关键字定义数组。

  • 不能使用auto推导模板参数:

    template <typename T>
    class Test{}
    
    int main(void){
        Test<int> t1;
        // Test<auto> t2 = t1;		错误,无法使用auto推导模板参数
        return 0;
    }
    

1.3 auto的应用

用于stl容器的遍历

  • C++98中:

    #include <map>
    #include <string>
    int main(void){
        map<int,string> person;
        map<int,string>::iterator it = person.begin();
        for(; it != person.end(); ++it){
            ...
        }
        return 0;
    }
    
  • C++11中,使用auto:

    #include <map>
    #include <string>
    int main(void){
        map<int,string> person;
        for(auto it = person.begin(); it != person.end(); ++it){
            ...
        }
        return 0;
    }
    

用于泛型编程:在使用模板时,有时并不知道变量应当定义什么类型,这时就可以使用auto:

#include <iostream>
#include <string>
using namespace std;

class A{
public:
    static int show(){
        return 1;
    }
};

class B{
public:
    static string show(){
        return "aaa";
    }
};

template <class T>
void func(){
    auto result = T::show();
    cout << result << endl;
}

int main(void){
    func<A>();
    return 0;
}

2. decltype

在某些情况下,我们希望通过表达式来获取某种类型,从而对变量进行定义,这时就可以使用decltype(是declare type的缩写)。

Eg:

int a = 10;
decltype(a) b = 100;
decltype(a+1.1) c = 3.14;
  • b被推导为int类型。
  • c被推导为double类型。

decltype的优势在于它能够在编译时推导复杂的表达式类型,而auto只能推导已初始化的变量类型。

2.1 推导规则

delctype的推导结果分情况而定:

  • 表达式是普通变量/普通表达式/类表达式,推导出的类型和表达式的类型一致。

  • 表达式是函数调用,使用decltypoe推导出的类型和函数返回值一致。

    class Test{...};
    //函数声明
    int func_int();                 // 返回值为 int
    int& func_int_r();              // 返回值为 int&
    int&& func_int_rr();            // 返回值为 int&&
    
    const int func_cint();          // 返回值为 const int。返回了一个右值
    const int& func_cint_r();       // 返回值为 const int&
    const int&& func_cint_rr();     // 返回值为 const int&&
    
    const Test func_ctest();        // 返回值为 const Test。返回的是一个右值,但是是一个对象
    
    //decltype类型推导
    int n = 100;
    decltype(func_int()) a = 0;		
    decltype(func_int_r()) b = n;	
    decltype(func_int_rr()) c = 0;	
    decltype(func_cint())  d = 0;	
    decltype(func_cint_r())  e = n;	
    decltype(func_cint_rr()) f = 0;	
    decltype(func_ctest()) g = Test();	
    
    • 变量a被推导为 int类型
    • 变量b被推导为 int&类型
    • 变量c被推导为 int&&类型
    • 变量d被推导为 int类型:因为func_cint()返回了一个右值,而对于右值而言,只有类才能携带const、volatile类型,因此需要忽略这两个限定符。
    • 变量e被推导为 const int &类型
    • 变量f被推导为 const int &&类型
    • 变量g被推导为 const Test类型。虽然func_ctest()返回了一个右值,但因为这个右值是一个对象,因此可以携带const、volatile类型。
  • 表达式不是一个变量并且是一个左值,或者表达式被()包围,那么使用decltype推导出来的是表达式类型的引用(如果有const、volatile不能忽略):

    class Test{
    public:
        int a;
    };
    
    int main(void){
        int x = 10, y = 20;
        decltype(x) a = 10;			
        decltype(x+y) b = 20;
        decltype(x = x + y) c = x;
    	
        const Test t;
        decltype(t.a) d = 10;
        decltype((t.a)) e = x;
        return 0;
    }
    
    • a:普通变量,推导出int类型。
    • b:普通表达式,推导出int类型
    • c:表达式,但最终返回左值,因此推导出int &类型。
    • d:普通变量,推导出int类型。
    • e:表达式被()包围,因此推导出cosnt int &类型。

3. 返回类型后置

引入:

在泛型编程中,有时会遇到一种情况:返回值的类型由函数的参数决定。例如:

template <typename R, typename X, typename Y>
R add(X x, Y y){
    return x + y;
}

上述代码可以,如果我们想通过decltype进行优化:

template <typename X, typename Y>
decltype(x+y) add(X x, Y y){
    return x + y;
}

这样会报错,因为delctype在编译阶段就要得出推导结果,但模板函数的参数类型却是在运行时才确定的,自然无法通过编译。为了解决这一问题,C++11引入了返回类型后置。

概述:

所谓返回后置类型,实际上就是将decltypeauto结合起来完成类型的推导。语法格式如下:

auto func(参数1, 参数2, ...) -> delctype(参数表达式)

通过上述语法,auto会自动追踪delctyple推导出的类型。所以函数可以修改为:

template <typename X, typename Y>
auto add(X x, Y y) -> decltype(x+y){
    return x + y;
}

标签:const,推导,int,auto,自动,类型,decltype
From: https://www.cnblogs.com/beasts777/p/17875397.html

相关文章

  • js自动播放【轮播图】
    demo<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>AutoCarousel</tit......
  • 基于DotNetty实现一个接口自动发布工具 - 背景篇
    故事背景小公司,单体项目,接口和页面都在一起,生产和测试环境都是Windows服务器和IIS,本地编译完成,把相关的页面和程序集拷贝到服务器上,尤其是涉及到多个页面,一个个页面找到对应的位置,再到服务器上找到对应的位置拷贝进去,甚至还有备份等操作,不胜其烦,因为历史遗留原因,......
  • sql-2.4+2.5数据库表的类型---engine
    CREATETABLE`student`(`id`intNOTNULLAUTO_INCREMENTCOMMENT'学号',`pwd`varchar(32)NOTNULLDEFAULT'123456'COMMENT'密码',`name`varchar(32)NOTNULLCOMMENT'名字',`address`varchar(60)NOTNULLCOMMENT......
  • 软件测试/人工智能|Python 数据类型解析:探索编程世界的多样性
    数据类型是编程中不可或缺的基本概念。在Python中,有多种数据类型,每种都有其独特的特点和用途。本文将带你深入了解常见的Python数据类型及其实际应用。引言在编程中,数据类型是对数据进行分类和组织的方式。Python中有多种数据类型,每种类型都有其自身的特性和功能。了解这......
  • 软件测试/人工智能|Python 数据类型转换解析:理解数据之间的灵活转换
    引言数据类型转换是指将一种数据类型的值转换为另一种数据类型的过程。在编程中,我们经常需要处理不同类型的数据,正确地进行类型转换是编写健壮程序的关键。常见的数据类型转换整数和浮点数转换为字符串#示例代码num_int=10num_float=3.14str_int=str(num_int)str......
  • 字符编码发展史_编码/解码_可变/不可变数据类型
    【一】什么是字符编码字符编码是一种将字符映射到数字编码的方法。由于计算机内部实际处理的是二进制数据,而字符是人类可读的符号,所以需要一种方式来表示和存储字符。字符编码就是将字符映射为对应的数字编码,以便计算机能够识别和处理字符。【二】字符编码的发展史字符编码的发......
  • 可变类型与不可变类型
    【垃圾回收机制】1.引用计数age=26m=age2,标记清除循环引用时,当其中一个变的没有意义,另外一个引用的就会清除不掉,使整个列表变成一个清除不掉的垃圾3.分代回收分代回收是一种垃圾回收的策略,其核心思想是根据对象的存活时间将其划分为不同的代【可变类型】可变类型:值变,但......
  • pipreqs 自动找到项目的所有组件和模块版本
    pipinstallpipreqs(适用于djangoFlask等)pipreqs./--encoding=utf-8找到当前项目目录下的所有组件和依赖H:\MyFlask>pipreqs./--encoding=utf-8十六.Flask基本项目目录搭建和pipreqs模块(组件和模块版本)virtualenv模块(创建虚拟环......
  • C++/Filesystem 文件类型
    #include<iostream>#include<filesystem>#include<string>namespacefs=std::filesystem;voiddemo_status(constfs::path&p,fs::file_statuss){std::cout<<p;switch(s.type()){casefs::file_type::none:......
  • 《最新出炉》系列初窥篇-Python+Playwright自动化测试-35-处理web页面定位toast-上篇
    1.简介在使用appium写app自动化的时候介绍toast的相关元素的定位,在WebUI测试过程中,也经常遇到一些toast(出现之后一闪而过,不留下一点点痕迹),那么这个toast我们这边如何使用playwright进行定位测试呢?今天宏哥就分两篇介绍一下。2.什么是toast?Android中的Toast是一种简易的消......