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

【C++11入门】新特性总结大全-Part2

【C++11入门】新特性总结大全-Part1-CSDN博客

上一篇我们提了一些我们常用但你可能不知道是C++11标准的一些特性。本节开始对上一节的内容进行一定的延伸。

1.auto与decltype

我们知道auto可以代替一些数据类型对变量进行定义,根据初始值自动给出最适数据类型。有时我们会遇到这样的情况:希望从表达式的类型推断出要定义的变量的类型,但是不详用该表达式的值来初始化变量。为了满足这一要求,C++11新标准引入了auto外的第二种类型说明符decltype

它的作用是选择并返回操作数的数据类型。在此过程中,编译器分析表达式并得到他的类型。却不实际计算表达式的值:

decltype(expression) variable;

其中 decltype后面的表达式可以是变量、函数、普通表达式。

T func(){/**/};

int a = 5;
double b = 3.14;

decltype(a) cp_I;//cp_I 是a的类型int
decltype(a*b) cp_D;//cp_D 是a*b的结果的类型double类型
decltype(func()) cp_T//cp_T 是 func()的返回值类型 T 类型。

在此之前我们有一个typeid().name();它可以将类型推断出来然后使用name()返回类型的字符串形式,但是它无法作为类型说明符对变量进行定义等操作。所以decltype的引入,带来了极大的方便。

delctype与引用

下面给出decltype与引用的专题讲解:

①decltype处理顶层const和引用的方式和auto有所不同,如果decltype使用的表达式是一个变量,则decltype返回该变量的类型,包括顶层const和引用在内:

const int ci=0, &cj =ci;
decltype(ci) x=0;//x的类型就是const int
decltype(cj) y=x;//y的类型就是const int&,y绑定到变量x
decltype(cj) z;  //err,z是一个引用,必须初始化。

因为cj是一个引用,decltype(cj)的结果就是引用类型。需要指出的是:引用从来都是作为其所指对象的同义词出现,只有用在decltype处是一个例外。 

有些表达式向decltype返回一个引用类型。一般来说当这种情况发生时,意味着该表达式的结果对象能作为一条赋值语句的左值:

int i=42, *p=&i, &r=i;
decltype(r+0) b;//正确:加法的结果是int 因此b是一个未初始化的int
decltype(*p) c;//错误,c是int& ,必须初始化

②因为r是一个引用,因此decltype(r)是一个引用类型。如果想结果是r所指的类型,可以把r作为表达式的一部分,如r+0,显然这个表达式的结果是一个int类型的具体值,而非一个引用。

③另一方面,如果表达式的内容是解引用操作,则decltype将得到引用类型。正如我们所熟悉的那样,解引用指针可以得到指针所指的对象,而且还能给这个对象赋值。因此,decltype(*p)的结果类型是int&,而非int。

④最后一点重要说明:decltype与auto的另一处重要区别是,decltype的结果类型与表达式形式密切相关。有一种情况需要特别注意:对于decltype所用的表达式来说,如果变量名加上了一对括号,则得到的类型与不加括号时会有不同。如果decltype使用的是一个不加括号的变量,则的打斗二结果就是该变量的类型;如果加上了一层或多层括号,编译器会把他当成一个表达式。变量是一种可以作为赋值语句左值的特殊表达式,所以这样decltype就会得到引用类型:

int i=l;
decltype(i) e;//e是一个未初始化的int变量
decltype((i)) d;//err,d是int&,必须初始化

总结: 

decltype(xxxx)推到结果是引用的情况

①xxxx是解引用,例如xxxx <- *p。

②xxxx是引用,例如int r&=i; xxxx <- r。

③xxxx是括号括起来的变量,例如,int i=0;xxxx <- (i)。

 decltype 是一个强大的工具,可以帮助开发者在不显式地写出类型的情况下,获取变量或表达式的类型。它在模板编程和泛型编程中特别有用,因为它允许编译器根据上下文自动推导类型。

2.列表初始化 与 initializer_list

在C++中,列表初始化和std::initializer_list是两个相关但不同的概念。下面是对它们的详细解释:

列表初始化

列表初始化是C++11引入的一种新的初始化方式。它使用花括号 {} 来初始化对象,可以用于基本数据类型、用户定义类型(如类和结构体)以及容器等。列表初始化具有以下特点:

直接初始化:可以使用花括号直接初始化变量。

int x{42};          // 列表初始化  
vector<int> vec{1, 2, 3}; // 初始化一个 vector

 避免窄化:列表初始化不允许从较大类型转换为较小类型(窄化)。

double d{3};      // 合法  
int i{3.14};      // 错误,窄化初始化

结构体和类:可以用来初始化结构体和类的成员。

struct Point { int x; int y; };  
Point p{1, 2}; // 初始化结构体

std::initializer_list

std::initializer_list 是一个用于支持列表初始化的类型,允许将一组元素传递给构造函数或函数。这种类型提供了便利,特别是在接收多个参数时。例如:

构造函数

class MyClass {  
public:  
    MyClass(std::initializer_list<int> list) {  
        // 可以使用 list 来处理初始化数据  
    }  
};  
MyClass obj{1, 2, 3}; // 使用 std::initializer_list 来初始化

 访问元素std::initializer_list 提供了 begin() 和 end() 方法,使得可以使用范围基于的循环等操作。

void printList(std::initializer_list<int> list) {  
    for (int value : list) {  
        std::cout << value << " ";  
    }  
}  
printList({1, 2, 3, 4}); // 可以直接传入 initializer_list

总结:

1.列表初始化 通过花括号 {} 语法来初始化对象,具有避免窄化等特性。

2.std::initializer_list 是一种特殊的类型,允许构造函数或函数接收一组初始化数据,背后实际上利用了列表初始化的特性。

3.这两者可以结合使用。例如,使用std::initializer_list作为参数的构造函数能够方便地接收列表初始化中的多个元素。

3.const 与 constexpr

const本身不属于C++11的新特性,但其延伸而来的constexpr标识符是C++11的重要特性。所以本节我们可能以const为对比,但着重谈后者。

在C++11中,引入了constexpr关键字,该关键字用于指示某个函数或变量可以在编译时进行求值。这是为了提高性能和代码优化,尤其是在需要常量表达式的上下文中。下面是对constexpr的详细解释:

常量表达式:


constexpr可以用于定义常量表达式,这意味着表达式在编译时就被计算出来,而不需要在运行时计算。

constexpr int square(int x) {  
    return x * x;  
}  

constexpr int result = square(5); // 在编译时计算,result 会被初始化为 25

 变量


constexpr 也可以用于变量的定义,确保该变量在编译时具有常量值。

constexpr int max_value = 100; // max_value 是一个编译时常量

类成员函数


C++11 允许在类中定义 constexpr 成员函数,使得可以在编译时使用这些函数。注意,constexpr成员函数必须只包含一个返回语句的表达式。

class Point {  
public:  
    constexpr Point(int x, int y) : x_(x), y_(y) {}  
    constexpr int getX() const { return x_; }  
    constexpr int getY() const { return y_; }  
private:  
    int x_, y_;  
};  

constexpr Point p(1, 2);  
constexpr int x = p.getX(); // x 在编译时就会被计算

注意事项:

  • 限制:在C++11中,constexpr函数的内容有限制,只能是具有单一 return 语句的简单表达式。不能有条件语句或循环(这些在C++14及以后可以使用)。

  • 使用场景:在需要在编译时已知常量值的情况下,constexpr非常有用,如数组大小、模板参数等。

  • 稳定性和优化:使用constexpr可以提高代码的稳定性和性能,因为编译器能够在编译时进行优化。

C++14和C++17的改进:在C++14及以后的版本中,constexpr的功能进行了扩展,使得可以在更复杂的上下文中使用,比如支持条件语句、循环等,使得constexpr函数的能力大大增强。

#include <iostream>  

constexpr int factorial(int n) {  
    return (n <= 1) ? 1 : n * factorial(n - 1);  
}  

int main() {  
    constexpr int fact5 = factorial(5); // 计算 5! 在编译时  
    std::cout << "5! = " << fact5 << std::endl; // 输出 5! = 120  
    return 0;  
}

感谢大家!


http://www.kler.cn/news/353413.html

相关文章:

  • 人工智能:开启未来生活与工作的新征程
  • Nacos相关问题
  • 《吉林大学学报(理学版)》
  • 鸿蒙开发:实现一个超简单的网格拖拽
  • 柔性数组的使用
  • 在Xshell中查看日志文件详情
  • Android中实现网络请求的方式有哪些?
  • 机器学习在聚合物及其复合材料中的应用与实践
  • 羲和数据清洗器002
  • 纯HTML实现标签页切换
  • uni-app 打包成app时 限制web-view大小
  • 【Linux修炼进程之权限篇】探讨Linux权限问题
  • 【Linux 从基础到进阶】数据加密与安全传输
  • ES 入门 -http-条件查询分页查询查询排序
  • js 对网页表格内容进行全选
  • 车载软件架构 --- 软件定义汽车开发:S32 CoreRide平台
  • 系统架构设计师教程 第16章 16.3 嵌入式系统软件架构设计方法 笔记
  • 代码随想录算法训练营第十七天|Day17二叉树
  • 【ChatGPT】如何通过 Prompt 优化 ChatGPT 的输出
  • 解锁C++多态的魔力:灵活与高效的编码艺术(上)
  • 【私有云盘搭建】Portainer CE部署NextCloud,轻松实现公网访问
  • Java 8 的内存结构
  • 基于MATLAB的语音信号处理系统
  • CV图像处理小工具——json文件转mask
  • 06_实现watch
  • 【排序】——2.快速排序法(含优化)