首页 > 其他分享 >2.auto、decltype和decltype(auto)的用法

2.auto、decltype和decltype(auto)的用法

时间:2023-08-02 22:11:31浏览次数:40  
标签:ci const int auto 用法 类型 decltype

2.auto、decltype和decltype(auto)的用法

1.auto

编程时常常需要把表达式的值赋给变量,这就要求声明变量时清楚的知道表达式的类型。然而有些情况是声明的变量的类型我们并不知道,比如在模板编程时。为了解决这个问题,C++11引入了auto类型说明符,用它来让编译器替我们去分析表达式所属的类型。

1.1auto的推导规则

规则1:声明为auto(不是auto&)的变量,忽视掉初始化表达式的顶层const。即对有const的普通类型(int 、double等)忽视const,对常量指针(顶层const)变为普通指针,对指向常量(底层const)的常量指针(顶层const)变为指向常量的指针(底层const)。
规则2:声明为auto&的变量,保持初始化表达式的顶层const或volatile 属性。
规则3:若希望auto推导的是顶层const,加上const,即const auto。

关于顶层和底层const是什么,可参考68.C++中的const - CodeMagicianT - 博客园 (cnblogs.com)

1.2auto

(1) auto例子

int i = 0, &ri = i;

auto a = i; //a为int型变量
auto a1 = ri; //a1为int型变量

auto p = &i;// &i 是一个普通int指针,p是一个整型指针int *
auto p1 = &ri; //同上
const int ci = 2, &rci = ci , ci2 = 9;

auto b = ci;//b为int型变量,因为规则1,b`并不是一个const int型的常量`
auto b1 = rci;//同上
b = 4;b1 = 5;//b和b1的值可以改变

auto cp = &ci;//cp是一个指向常量的指针const int* ,因为&ci对常量对象取地址是底层const,无顶层const属性
cp = &ci2;//cp的指向可以改变

下面看忽视顶层const指针的例子:

int z = 9,z1 = 10;

int* const pz1 = &z;//pz1为int* const(顶层const)
const int* pz2 = &z;//pz2为const int* (底层const)
const int* const pz3= &z;//pz3为const int* const(同时包含底层和顶层const)

auto apz1 = pz1;//apz1为int*
auto apz2 = pz2;//apz2为const int*
auto apz3 = pz3;//apz3为const int*

对于pz1和pz3,它们都有顶层const属性,所以apz1和apz3都会忽略顶层const属性。

这里注意:对常量对象取地址总是看作为一种底层的const,即不是对指针(也就是指向)的常量,而是对指针指向内存中的值是常量。所以上面的&ci是const int*型。

(2)const auto例子

int i = 0, &ri = i;
const int ci = 2, &rci = ci ;

const auto cb = i; //cb为const int型。因为规则3,cb被提升为const
const auto cb1 = ci; //同上

const auto ca1 = &i;//cal为常量指针。&i本是int*,因为规则3,强行将cal提升为常量指针int *const
const auto ccp = &ci;//本来&ci为const int *,因为规则3,加了const后,提示为const int * const

1.3声明为auto引用:auto&

例子:

int i = 0, &ri = i;
const int ci = 2, &rci = ci ;
	
auto & j = i; //j为int &
auto & k = ci; // k为const int &
auto & h = 42; //错误,不能将非常量引用绑定字面值,这是引用&规则决定的

const auto &j2 = i; //j2为const int &,因为规则3,j2被提升为顶层const
const auto &k2 = ci; //k2为const int &
const auto &h2 = 42; //正确,可以为常量绑定字面值 

auto& m =  &i;//Error,无法从“int *”转换为“int *&” ,这是引用&规则决定的
auto& m1 = &ci;// Error,无法从“const int *”转换为“const int *&” ,这是引用&规则决定的
const auto &m2 = &i;//m2为int * const &
const auto &m3 = &ci;//m3为const int * const &

上例子中有3条是错误的,原因是:引用不能绑定表达式的计算结果,除非使用const。并且对于 普通指针而言,它提升到顶层const,只能为常量指针,而不能为指向常量的指针 (原因可参考:为什么无法从“int *”转换为“const int *&”?)。所以后两个都带常量指针属性,最后一个由于本身就是底层的const(即指向常量的指针),所以为指向常量的常量指针。

有关对于指针的引用,我在无法从“int *”转换为“int *&”?详解C++引用(&)使用方法中有详细的介绍,可供大家参考。
有关常量指针和指向常量的指针,我在详解const引用和常量指针、指向常量的指针有一小节详细介绍,可供大家参考。

小结:使用auto &的时候不光需要知道auto&的推到规则,还要明白引用(&)的使用限制。我们首先看的就是&的使用限制。

1.4auto在编程时真正的用途

上面我们详细介绍了auto的使用规则,但它仅仅是使用规则而已,在实际编程中我们在明确变量类型情况下,还是使用明确的类型。Auto真正在编程时的实际应用如下:

内容参考至:https://www.cnblogs.com/QG-whz/p/4951177.html

(1)代替冗长复杂的变量声明

我们在使用迭代器时常常会这样操作:

list<int> l1;
l1.push_back(1);
l1.push_back(2);
l1.push_back(3);

for (list<int>::iterator i = l1.begin(); i != l1.end(); i++)
{
	cout << i.operator->() << endl;
	cout << *i << endl;
}

这样list<int>::iterator i = l1.begin()的声明迭代器i看起来繁琐冗长,我们实际可以用auto代替:auto i = l1.begin();

(2)定义模板参数时,用于声明依赖模板参数的变量

template <typename _Tx,typename _Ty>
void Multiply(_Tx x, _Ty y)
{
    auto v = x+y;
    std::cout << v;
}

如上所示:我们获取x+y的值,但是x、y都是模板类型,我们无法知道其类型,这时就可以使用auto。

(3)模板函数依赖于模板参数的返回值

template <typename _Tx, typename _Ty>
auto multiply(_Tx x, _Ty y)->decltype(x*y)
{
    return x*y;
}

上面的例子中,返回值依赖于xy的类型,这里我们需要提前查询xy的数据类型,需要用到decltype操作符,它是C++11标准引入的新的运算符,其目的也是解决泛型编程中有些类型由模板参数决定,而难以表示它的问题。
注意:auto在这里的作用也称为返回值占位,它只是为函数返回值占了一个位置

有关decltype,参考:有auto为什么还要decltype ?详解decltype的用法

参考:C++ auto用法及应用详解

2.decltype

auto和decltype推导类型的区别

既然auto可以推导变量的类型,为什么C++11还引进decltype类型说明符呢?关于这一点,C++ Primer中这样写道:有时希望从表达式的类型推断出要定义的变量的类型(这一点auto可以做到),但是不想用该表达式的值初始化变量(auto依赖这一点才能推导类型)。请看下面的例子:

int a = 10, b = 11;
auto c = a + b; //c为int型
decltype(a + b) d ; //d为int型

auto通过初始化它的表达式来推断c的类型,也就是说,auto推导变量依赖于初始化它的表达式,并且auto声明的变量必须初始化;而decltype是直接通过某一个表达式来获取数据类型,从而定义d的类型。

2.1decltype变量

形式:decltype(var)

和auto不同,decltype会保留const属性和引用属性,看下面的例子:

const int ci = 0, &cj = ci;

decltype(ci) x = 0;//x的类型为const int
decltype(cj) y = x; //y的类型为const int&
decltype(cj) z; //错误,因为z的类型为const int&,必须初始化

auto w = ci;//w的类型是int
w = 9;
auto n = cj;//n的类型是int

2.2decltype表达式

形式:decltype(expr)

decltype表达式时,返回的类型根据表达式的结果不同而不同:expr返回左值,得到该类型的左值引用;expr返回右值,得到该类型。

(1)表达式做右值

如下面的例子中:
尽管r是引用类型,但是r+0是一个具体的值,只能做右值,值对应的类型是int型,所以b为int类型。

int i = 42, &r = i;
decltype(r + 0) b; //b类型是int,而不是int&

(2)表达式能做左值

结论:表达式能做左值,推导为类型的引用。

表达式能做左值有两个典型的例子:decltype (*p)和decltype ((ii))。请看下面的例子:

●对于解引用*p, 它代表的是p指向地址中的值,同时我们可以给这个值赋值,即为左值。所以,decltype(*p)是int& ,这样才能有给绑定变量的值赋值的特点。
●ii是一个变量,加上括号后变为表达式,即(ii)是一个表达式,又我们可以ii赋值,即为左值。所以,decltype((var))永远是一个引用类型,decltype((ii))声明变量d时,d就为int&类型。

int ii = 42, *p = &ii;
decltype(*p) c;//错误,c是int&,必须初始化
decltype((ii)) d;//错误,d是int&,必须初始化

2.3 decltype 函数

(1)decltype(f())

直接看下面的例子:

decltype(f()) sum = x; 

其中,sum的类型就是函数f的返回类型,sum的类型就是假如函数f被调用,它会返回那个类型。注意:若是函数f的返回值为void,编译报错
再看下面的例子:
m的类型为int型;m2的类型为double型。

template <typename T>
T add(T a, T b)
{
	return a+b;
}

decltype(add(1,2)) m = 10; //m的类型是int
decltype(add(1.0,2.0)) m2 = 20; //m2的类型是double

(2)decltype(f)

看下面的例子,decltype(add_to)直接返回函数类型,所以pf是一个函数指针。

int add_to(int a, int b)
{
	return a + b;
}

decltype(add_to) *pf = add_to; //pf就是一个函数指针,类型为int (int,int)
pf(1,2);

那么可以返回模板函数的函数指针吗?如下,显然是不行的,因为模板函数依赖于参数列表,只根据函数名是无法推断函数类型的,所以说函数指针pf的类型无法确认

template <typename T>
T add_to(T a, T b)
{
	return a + b;
}

decltype(add_to) *pf = add_to; 
pf(1,2);

和模板函数一样,如果函数是重载的,也无法通过函数名来推断返回的函数类型,那么也无法返回函数指针,如下面的例子中声明pf为函数指针是错误的。

int add_to(int a, int b)
{
	return a + b;
}

int add_to(int a, int b,int c)
{
	return a + b +c;
}
decltype(add_to) *pf = add_to; 
pf(1,2);

C++ 11 中decltype的主要作用

Decltype在C++11中的主要作用是用于申明返回值类型依赖于其参数类型的模板函数。例子如下:

template <typename _Tx, typename _Ty>
auto multiply(_Tx x, _Ty y)->decltype(x*y)
{
    return x*y;
}

注意这里的auto并没有做任何类型推断(关于auto的用法:参考C++ auto用法及应用详解),只是用来表明这里使用的是C++11 的拖尾返回类型(trailing return type)语法,也就是函数返回类型将在参数列表之后进行声明(在"->"之后),优点是可以使用函数参数来声明函数返回类型(如果将返回类型放置于函数之前,这里的参数x和y还没有被声明,因此不能被使用)。

参考:有auto为什么还要decltype ?详解decltype的用法

3.decltype(auto)

标签:ci,const,int,auto,用法,类型,decltype
From: https://www.cnblogs.com/codemagiciant/p/17601906.html

相关文章

  • Java中synchronized的用法
    在Java中,synchronized是一种同步机制,可用于控制多个线程在访问共享资源时的并发问题。synchronized可以修饰方法和代码块,以确保共享资源的互斥访问,从而避免不同线程间访问该资源时发生冲突。synchronized的用法包括以下几种:同步方法使用synchronized修饰方法,可以确保在多个线程访问......
  • @RequiredArgsConstructor 用法
    在我们写controller或者Service层的时候,需要注入很多的mapper接口或者另外的service接口,这时候就会写很多的@Autowired注解,代码看起来很乱lombok提供了一个注解:@RequiredArgsConstructor(onConstructor=@_(@Autowired))写在类上可以代替@Autowired注解,需要注意的是在注入时需要......
  • jkd8用法
    --多线程处理 CompletableFuture<Object>future2=ThreadUtil.supplyAsyncWithContext(()->{      //进行中状态的活动      getAndUpdateCurrentNextAccounts(currentNextAccountList,userId,roleMap,userCNMap);      retur......
  • .NET Core如何使用第三方容器Autofac
    首先先了解一下什么是AutofacAutofac用于在.NETCore应用程序中管理组件的生命周期和依赖关系。我们在开发一个项目的时在Program中注入依赖注入的生命周期,项目工程比较大的时候我们就要实现很多注入,最致命的缺点就是耽误太多时间,为解决这一问题的最好解决方法就是使用到Autof......
  • Vue进阶用法4
    Vue进阶用法4vue3介绍1.性能的提升打包大小减少41%初次渲染快55%,更新渲染快133%内存减少54%2.源码的升级使用Proxy代替defineProperty实现响应式重写虚拟DOM的实现和Tree-Shaking3.拥抱TypeScriptVue3可以更好的支持TypeScript4.新的特性......
  • Vue进阶用法1
    Vue进阶用法1计算属性#如果{{函数()}},每次页面刷新,函数都会重新执行#函数---》当属性来使用,缓存<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Title</title><scriptsrc="./js/vue.js"......
  • Vue进阶用法2
    Vue进阶用法2vue项目目录介绍myfirstvue#项目名字node_modules#文件夹,内部有很多当前项目依赖的模块,可以删除,npminstallpublic#文件夹-favicon.ico#网站小图标-index.html......
  • Vue进阶用法3
    Vue进阶用法3Vuex的使用#vue的插件,增强了vue的功能,在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信#Vuex的使用流程 -state:存数据的地址-actions:服务员,中转站......
  • @Autowired 和 @Resource的区别
    @Autowired和@Resource都可以用于注入Bean对象,并且都可以自动装配依赖关系,但他们主要的区别在于:1.使用的注解不同@Autowired是Spring提供的注解,而@Resource是JSR-250规范提供的注解。2.默认情况下注入的方式不同@Autowired默认按照类型装配依赖对象,当发现有多个Bean满足依......
  • JSON格式电商数据API接口,便捷式用法
    item_search-按关键字搜索商品请求参数注册Key和secret测试请求参数:q=女装&start_price=0&end_price=0&page=1&cat=0&discount_only=&sort=&page_size=40&seller_info=no&nick=&seller_info=&nick=&ppath=&imgid=&filter=参数说明:q:搜索关键字cat:......