当前位置: 首页 > news >正文

C++11 之 auto decltype

文章目录

      • auto
      • decltypes
      • auto 和 decltype 的配合—返回值类型后置

关于 c++11 新特性,最先提到的肯定是类型推导,c++11 引入了 auto 和 decltype 关键字,使用他们可以在编译期就推导出变量或者表达式的类型,方便开发者编码也简化了代码。

auto

auto:让编译器在编译期间就推导出变量的类型,可以通过 = 右边的类型推导出变量的类型
auto 关键字基本的使用语法如下:auto name = value;
示例:

auto a = 10;  // 10 是 int 型,可以自动推导出 a 是 intint i = 10;
auto b = i;  // b 是 int 型auto d = 2.0;  // d 是 double 型auto url = "http://c.biancheng.net/cplus/";  // 由双引号包围起来的字符串是 const char* 类型,所以推导出变量 url 的类型是 const char*,也即一个常量指针。

auto 的限制

  • auto 的使用必须马上初始化,否则无法推导出类型;
  • auto 在一行定义多个变量时,各个变量的推导不能产生二义性,否则编译失败;
  • auto 不能用作函数参数;
  • 在类中 auto 不能用作非静态成员变量;
  • auto 不能定义数组,可以定义指针;
  • auto 无法推导出模板参数。
    示例:
int i = 10;
auto a = i, &b = i, *c = &i;  // a是int,b是i的引用,c是i的指针,auto就相当于intauto d = 0, f = 1.0;  // error,0和1.0类型不同,对于编译器有二义性,没法推导auto e;  // error,使用auto必须马上初始化,否则无法推导类型void func(auto value) {}  // error,auto不能用作函数参数class A {auto a = 1;         // error,在类中 auto 不能用作非静态成员变量static auto b = 1;  // error,这里与 auto 无关,正常 static int b = 1 也不可以,因为静态成员变量不能在类中初始化static const auto int c = 1;  // ok
};void func2() {int a[10] = {0};auto b = a;      // okauto c[10] = a;  // error,auto不能定义数组,可以定义指针vector<int> d;vector<auto> f = d;  // error,auto无法推导出模板参数
}

对引用的处理
当表达式的类型为引用时, auto 会抛弃引用类型,直接推导出它的原始类型。

int n = 10;
int& r1 = n;// auto推导
auto r2 = r1;
r2 = 20;
cout << n << ", " << r1 << ", " << r2 << endl;
// 打印结果:10, 10, 20

推导规则

首先,介绍下,这里的cv是指 cv 限定符,是 const 和 volatile 关键字的统称:

  • const 关键字用来表示数据是只读的,也就是不能被修改;
  • volatile 和 const 是相反的,它用来表示数据是可变的、易变的,目的是不让 CPU 将数据缓存到寄存器,而是从原始的内存中读取。

接着,看一下 auto 关键字对 cv 限定符的推导规则

  • 在不声明为引用或指针时,auto会忽略等号右边的引用类型和 cv 限定
  • 在声明为引用或者指针时,auto会保留等号右边的引用和 cv 属性
int i = 0;
auto* a = &i;  // a是int*
auto& b = i;   // b是int&
auto c = b;    // c是int,忽略了引用const auto d = i;  // d是const int
auto e = d;        // e是intconst auto& f = e;  // f是const int&
auto& g = f;        // g是const int&

什么时候使用 auto?
这里没有绝对答案,个人认为:在不影响代码可读性的前提下尽可能使用 auto 是合适的,复杂类型就使用 auto,但对于像 int、double 这种基础数据类型就没有必要使用 auto,看下面这段代码:

auto func = [&] {cout << "xxx";
};  // 对于 func 你难道不使用 auto 吗,反正我是不关心 lambda 表达式究竟是什么类型。auto asyncfunc = std::async(std::launch::async, func);
// 对于 asyncfunc 你难道不使用 auto 吗,我是懒得写 std::futurexxx 等代码,而且我也记不住它返回的究竟是什么...

decltypes

上面介绍 auto 用于推导变量类型,而 decltype 则用于推导表达式类型,这里只用于编译器分析表达式的类型,表达式实际不会进行运算,decltype 也是编译时期进行自动类型推导。
decltype 关键字基本的使用语法如下:decltype(exp) varname = value;

  • exp 是表达式,decltype(exp) 和exp 类型相同
  • exp 是函数调用,decltype(exp) 和函数返回值类型相同
  • 其它情况,若 exp 是左值,decltype(exp) 是 exp 类型的左值引用

示例:

int func() { return 0; }
decltype(func()) i;  // i为int类型int x = 0;
decltype(x) y;      // y是int类型
decltype(x + y) z;  // z是int类型int a = 0, b = 0;
decltype(a + b) c = 0;   // c是int,因为(a+b)返回一个右值
decltype(a += b) d = c;  // d是int&,因为(a+=b)返回一个左值

【注意1】decltype 不会像 auto 一样忽略引用和 cv 属性,decltype 会保留表达式的引用和 cv 属性:

cont int &i = 1;
decltype(i) b = 2; // b是const int&

【注意2】当表达式的类型为引用时,auto 和 decltype 的推导规则也不一样;decltype 会保留引用类型,而 auto 会抛弃引用类型,直接推导出它的原始类型。请看下面的例子:

int n = 10;
int& r1 = n;// auto推导
auto r2 = r1;
r2 = 20;
cout << n << ", " << r1 << ", " << r2 << endl;// decltype推导
decltype(r1) r3 = n;
r3 = 99;
cout << n << ", " << r1 << ", " << r3 << endl;
// 打印结果
// 10, 10, 20
// 99, 99, 99

【注意3】原则上讲,exp 就是一个普通的表达式,它可以是任意复杂的形式,但是我们必须要保证 exp 的结果是有类型的,不能是 void;例如,当 exp 调用一个返回值类型为 void 的函数时,exp 的结果也是 void 类型,此时就会导致编译错误。

只能使用 decltype 场景
auto 只能用于类的静态成员,不能用于类的非静态成员(普通成员),如果我们想推导非静态成员的类型,这个时候就必须使用 decltype 了。

#include <vector>
using namespace std;template <typename T>
class Base {
public:void func(T& container) { m_it = container.begin(); }private:decltype(T().begin()) m_it;  //注意这里
};int main() {const vector<int> v;Base<const vector<int>> obj;obj.func(v);return 0;
}

auto 和 decltype 的配合—返回值类型后置

auto 和 decltype 一般配合使用在推导函数返回值的类型问题上。
下面这段代码:

template <typename T, typename U>
return_value add(T t, U u) {  // t和v类型不确定,无法推导出return_value类型return t + u;
}

上面代码由于 t 和 u 类型不确定,那如何推导出返回值类型呢,我们可能会想到这种

template <typename T, typename U>
decltype(t + u) add(T t, U u) {  // t和u尚未定义return t + u;
}

这段代码在 c++11 上是编译不过的,因为在 decltype(t +u) 推导时,t 和 u 尚未定义,就会编译出错,所以有了下面的叫做返回类型后置的配合使用方法:

template <typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {return t + u;
}

返回值后置类型语法通过 auto 和 decltype 结合起来使用,目的为了解决函数返回值类型依赖于参数但却难以确定返回值类型的问题。

http://www.lryc.cn/news/16924.html

相关文章:

  • 论文笔记:How transferable are features in deep neural networks? 2014年NIP文章
  • python基于flask共享单车系统vue
  • C++11 之模板改进
  • Linux - POSIX信号量,基于环形队列的生产者消费者模型
  • 学习Flask之七、大型应用架构
  • CentOS9下编译FFMPEG源码
  • 炼石:八年饮冰难凉热血,初心如磐百炼成钢
  • Python基本数据类型
  • 【MySQL进阶】 锁
  • javascript高级程序设计第四版读书笔记-第五章 基本引用类型
  • 《爆肝整理》保姆级系列教程python接口自动化(二十一)--unittest简介(详解)
  • 【C++的OpenCV】第四课-OpenCV图像常用操作(一):Mat对象深化学习、灰度、ROI
  • Propargyl-PEG1-SS-PEG1-PFP ester,1817735-30-0,炔基应用于生物标记
  • 产品运营︱用户活跃度低的解决方法
  • 【华为OD机试模拟题】用 C++ 实现 - 求最大数字
  • 吉卜力风格水彩画怎么画?
  • Python的类变量和对象变量声明解析
  • #笨鸟先飞 猴博士电路笔记 第一篇 电路基础
  • 快捷式~node.js环境搭建
  • ZooKeeper实现分布式队列、分布式锁和选举详解
  • 【swift】swift quick start
  • 浅谈volatile关键字
  • 10 种 Spring事务失效场景
  • 重读《DOOM启世录》
  • 巧用性格上的差异来组建团队
  • Leetcode11. 盛最多水的容器
  • Java笔记026-集合/数组、Collection接口、ArrayList、Vector、LinkedList
  • Hive学习——分桶抽样、侧视图与炸裂函数搭配、hive实现WordCount
  • 大数据算法
  • 非暴力沟通读书笔记