C++14 新特性

news2024/12/25 9:34:24

C++14 新特性

  • C++14 新特性
    • 变量模板
    • 通用lambda表达式
    • 常量表达式
    • 二进制字面量
    • 数组大小自动推导
    • make_unique
    • exchange
    • integer_sequence
    • constexpr函数的扩展
    • 变长参数模板的扩展

C++14 新特性

C++14 is a minor but important upgrade over C++11, and largely “completes C++11.”

变量模板

C++14可以定义变量模板:

template<class T>
constexpr T pi = T(3.1415926535897932385L); // variable template

int main()
{
    std::cout << pi<double> << std::endl;
    std::cout << pi<float> << std::endl;
    std::cout << pi<int> << std::endl;
    return 0;
}

运行结果:

在这里插入图片描述

如果想在类内部定义变量模板,那么需要定义静态变量,同时也可以对模板变量进行特化。

struct Limits
{
    template<typename T>
    static const T min; // 声明静态成员模板
};
 
template<typename T>
const T Limits::min = { }; // 定义静态成员模板,全部使用默认值

// 下面三个是模板变量的特化
template<>
const float Limits::min<float> = 4.5;

template<>
const double Limits::min<double> = 5.5;

template<>
const std::string Limits::min<std::string> = "hello";

int main()
{
    std::cout << Limits::min<int> << std::endl;//0
    std::cout << Limits::min<float> << std::endl;//4.5
    std::cout << Limits::min<double> << std::endl;//5.5
    std::cout << Limits::min<std::string> << std::endl;//hello
    return 0
}

通用lambda表达式

C++14引入了通用lambda表达式,可以使用auto关键字作为参数类型和返回类型,使得lambda表达式更加灵活。

通用lambda表达式的语法如下:

[ captures ] ( auto&&... params ) -> decltype(auto) { body }

其中,captures是lambda表达式的捕获列表,params是lambda表达式的参数列表,decltype(auto)表示返回类型会根据body自动推导出来。

例如,以下代码展示了一个使用通用lambda表达式的例子:

int main()
{
    auto add = [](auto x, auto y)
    {
        return x + y;
    };
    
    std::cout << add(1, 2) << std::endl; // 输出 3
    std::cout << add(1.5, 2.5) << std::endl; // 输出 4
    
    return 0;
}

在这个例子中,lambda表达式的参数类型和返回类型都使用了auto关键字,使得它可以接受不同类型的参数,并返回相应的结果。

常量表达式

C++14中,常量表达式是指在编译时可以计算出结果的表达式,它可以用于声明常量、数组大小、枚举值等。

C++14中新增了一些常量表达式的规则:

  1. 函数可以被声明为常量表达式,只要函数满足以下条件:
    • 函数的返回值类型是字面类型(literal type)
    • 函数体只包含符合常量表达式要求的语句
  2. 可以使用if和switch语句,只要它们的条件表达式是常量表达式,并且语句体也是符合常量表达式要求的语句。
  3. 可以使用循环语句,只要循环次数是常量表达式。
  4. 可以使用lambda表达式,只要它符合常量表达式的要求。

示例:

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

int main()
{
    constexpr int n = 5;
    int arr[factorial(n)]; // 使用常量表达式计算数组大小
    
    return 0;
}

在上面的例子中,函数factorial被声明为常量表达式,并用于计算数组arr的大小。由于n是一个编译时常量,因此可以在编译时计算出factorial(n)的值,从而确定数组的大小。

二进制字面量

C++14引入了二进制字面量,允许程序员使用二进制表示法来表示整数值。

二进制字面量以前缀0b或0B开头,后面跟着一串二进制数字。例如,0b101010表示十进制数42。

二进制字面量提供了一种简单而方便的方法来表示位模式,这对于编写低级别的系统代码或进行位运算非常有用。

示例:

int main()
{
    int a = 0b101010;
    std::cout << a << std::endl; //输出42
    return 0;
}

数组大小自动推导

在C++14中,可以使用auto关键字和初始化列表来实现数组大小的自动推导。具体来说,可以使用以下语法:

auto arr = {1, 2, 3, 4}; // 自动推导为std::initializer_list<int>

在这个例子中,编译器会自动推导出arr的类型为std::initializer_list<int>,而数组的大小也会自动根据初始化列表的元素个数进行推导。因此,上述代码等价于下面的代码:

int arr[] = {1, 2, 3, 4}; // 数组大小为4

需要注意的是,这种自动推导方式只适用于静态数组,而对于动态数组来说,还需要使用new运算符手动分配内存。另外,由于std::initializer_list是一个轻量级的容器,因此它的性能可能不如普通数组。

make_unique

C++14中的std::make_unique是一个函数模板,用于创建一个std::unique_ptr对象并将其初始化为一个新对象。它接受一个可变参数列表和一个构造函数的参数列表,用于在创建新对象时传递给构造函数。

make_unique的语法如下:

template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args);

其中,T是要创建的对象的类型,Args是传递给构造函数的参数列表。make_unique返回一个std::unique_ptr对象,该对象拥有指向新对象的所有权。

使用make_unique可以避免手动创建std::unique_ptr对象并进行new操作,从而避免了内存泄漏和错误的可能性。它还可以提高代码的可读性和简洁性。

下面是一个使用make_unique创建一个动态分配的对象的例子:

#include <memory>
#include <iostream>

class MyClass
{
public:
    MyClass(int value) : m_value(value)
    {
        std::cout << "MyClass constructor called with value: " << m_value << std::endl;
    }
    ~MyClass()
    {
        std::cout << "MyClass destructor called with value: " << m_value << std::endl;
    }
private:
    int m_value;
};

int main()
{
    auto ptr = std::make_unique<MyClass>(42);
    return 0;
}

在这个例子中,我们使用make_unique创建了一个动态分配的MyClass对象,并将其初始化为值42。当程序退出main函数时,指向该对象的指针ptr将被自动销毁,并调用MyClass的析构函数。

需要注意的是,make_unique不能用于创建数组,因为std::unique_ptr不支持动态数组。如果需要创建动态数组,应该使用std::vector或std::array。

exchange

std::exchange是C++14中引入的一个函数模板,它定义在头文件中。这个函数的作用是交换一个对象的值并返回其旧值。

std::exchange的函数原型如下:

template<class T, class U = T>
T exchange(T& obj, U&& new_value);

其中,T是要交换值的对象的类型,obj是要交换值的对象的引用,new_value是新值,U是新值的类型。

这个函数的作用是将obj的值用new_value替换,并返回obj原来的值。这个操作是原子的,所以在多线程环境中使用是安全的。

下面是一个使用std::exchange的例子:

#include <iostream>
#include <utility>
int main()
{
    int x = 1;
    int y = std::exchange(x, 2);
    std::cout << "x = " << x << ", y = " << y << std::endl; //输出x = 2, y = 1
    return 0;
}

在这个例子中,我们使用std::exchange将x的值从1替换成2,并将原来的值1赋给了y。

integer_sequence

C++14中的std::integer_sequence是一个模板类,用于创建一个整数序列。它可以用于编写与模板参数数量和类型无关的代码,例如元编程和模板元函数。

std::integer_sequence有两个模板参数:第一个是整数类型(通常是std::size_t),第二个是整数序列的长度。例如,std::integer_sequence<std::size_t, 3>表示一个包含三个std::size_t类型整数的序列。

std::make_integer_sequence模板函数可以用来创建一个整数序列。它接受一个整数类型和一个整数序列长度作为参数,并返回一个std::integer_sequence对象。例如,std::make_integer_sequence<std::size_t, 5>将返回一个包含0到4的std::size_t类型整数的序列。

std::index_sequence是std::integer_sequence的特化版本,其中第一个模板参数固定为std::size_t。它通常用于访问元组中的元素,因为元组中的元素是按照索引顺序存储的。

使用std::integer_sequence和std::make_integer_sequence可以实现可变参数模板的参数展开,例如:

template<typename... Ts>
void foo(Ts... args)
{
    bar(std::make_index_sequence<sizeof...(Ts)>{}, args...);
}

template<typename... Ts, std::size_t... Is>
void bar(std::index_sequence<Is...>, Ts... args)
{
    // 访问args中的元素,例如:
    int x = std::get<Is>(std::make_tuple(args...));
}

在上面的例子中,foo函数接受任意数量和类型的参数,并将它们传递给bar函数。bar函数使用std::index_sequence来访问args中的元素。

#include <iostream>
#include <utility>

template<typename... Ts, std::size_t... Is>
void print_helper(const std::tuple<Ts...>& tpl, std::index_sequence<Is...>)
{
    ((std::cout << std::get<Is>(tpl) << ' '), ...);
    std::cout << '\n';
}

template<typename... Ts>
void print(Ts... args)
{
    std::tuple<Ts...> tpl(args...);
    print_helper(tpl, std::make_index_sequence<sizeof...(Ts)>());
}

template<typename... Ts>
void foo(Ts... args)
{
    print(args...);
}

int main()
{
    foo(1, 2.5, "hello");  // 输出:1 2.5 hello
    return 0;
}

在上面的例子中,print_helper函数使用std::index_sequence来展开std::tuple中的元素,并将它们打印到控制台上。print函数创建一个std::tuple对象,并使用std::make_index_sequence来创建一个std::index_sequence对象,然后将它们传递给print_helper函数。foo函数使用print函数来打印参数。

constexpr函数的扩展

关键字 constexpr 是在 C++11 中引入的,并在 C++14 中进行了改进。 它表示 constant(常数)表达式。 与 const 一样,它可以应用于变量:如果任何代码试图 modify(修改)该值,将引发编译器错误。 与 const 不同,constexpr 也可以应用于函数和类 constructor(构造函数)。 constexpr 指示值或返回值是 constant(常数),如果可能,将在编译时进行计算,这个在很多时候可以提高程序在运行时的效率。

在C++11中,constexpr要求非常严格,这就导致了constexpr的并不是那么易用。

C++11中:

  1. constexpr修饰变量,要求变量必须是可以在编译器推导出来;
  2. constexpr修饰函数(其实就是修饰函数返回值),除了可以包含 using 指令、typedef 语句以及 static_assert 断言外,只能包含一条 return 返回语句;
  3. constexpr同时可以修饰构造函数,但是也会要求使用这个构造函数时,可以在编译器就把相关的内容全部推导出来。

C++14中对constexpr函数的扩展主要包括以下几个方面:

  1. 放宽了对constexpr函数的限制:在C++11中,constexpr函数只能包含一些简单的语句,比如赋值语句和return语句,而在C++14中,constexpr函数可以包含一些复杂的语句,比如if语句和循环语句。
  2. 允许constexpr函数调用非constexpr函数:在C++11中,constexpr函数只能调用其他constexpr函数,而在C++14中,constexpr函数可以调用非constexpr函数,只要这些函数的返回值可以在编译时确定。
  3. 允许constexpr函数返回void类型:在C++11中,constexpr函数必须返回一个常量表达式,而在C++14中,constexpr函数可以返回void类型,只要函数体中的语句都是常量表达式。
  4. 允许constexpr函数有多个参数:在C++11中,constexpr函数只能有一个参数,而在C++14中,constexpr函数可以有多个参数,只要这些参数都是常量表达式。
  5. 允许constexpr函数有局部变量:在C++11中,constexpr函数不能有局部变量,而在C++14中,constexpr函数可以有局部变量,只要这些变量都是常量表达式。

总的来说,C++14中对constexpr函数的扩展使得这种函数更加灵活和实用,可以用于更多的场景,提高代码的可读性和可维护性,但仍然需要在编译期间就可以计算出全部内容。

变长参数模板的扩展

C++14中引入了变长参数模板的扩展,可以使用类似于函数参数的语法来定义模板参数列表。这个特性被称为“参数包扩展”或“参数模板扩展”。

参数模板扩展允许在模板参数列表中使用省略号(…)来表示一个可变数量的模板参数。这些参数被称为“参数包”,可以在模板定义中使用。

例如,下面的代码定义了一个可变参数模板,用于在编译时计算一组数字的总和:

template<typename... Args>
int sum(Args... args)
{
    return (args + ...);
}

在这个例子中,省略号表示Args是一个可变数量的模板参数。在函数体中,使用了折叠表达式(fold expression)来计算所有参数的总和。

使用参数模板扩展可以极大地简化代码,特别是在处理不同数量的参数时。例如,可以定义一个可变参数模板来打印任意数量的值:

template<typename... Args>
void print(Args... args)
{
    (std::cout << ... << args) << '\n';
}

在这个例子中,省略号表示Args是一个可变数量的模板参数。在函数体中,使用了折叠表达式来将所有参数输出到标准输出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1106225.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

找免费音效素材,就上这6个网站,无版权可商用

很多视频剪辑或从事自媒体工作的朋友都不知道去哪里找免费的音效素材&#xff0c;很多网站需要付费或会员才能下载&#xff0c;还不能商业用途。如何找到即免费还能商用的音效素材&#xff1f; 本期就把我收藏多年的6个免费可商用的音效素材网站分享给大家&#xff0c;以后就不…

快速了解服务器单CPU与双CPU

​  在当今快节奏的技术环境中&#xff0c;用户们对功能强大且高效的服务器配置需求不断增长。CPU作为构成任何计算基础设施的骨干&#xff0c;服务器的“大脑”&#xff0c;负责执行计算、控制数据流并协调各个组件之间的任务&#xff0c;是服务器选择硬件中的重要一环。因此…

CSS 之 display属性详解

一、总览 ​ CSS的 display 属性用于设置元素的显示类型&#xff0c;或设置其子元素的布局类型。 display属性值的适用性取决于元素的类型和上下文。某些属性值只适用于特定类型的元素&#xff0c;使用时需注意兼容性和语义化。 ​ 其属性值共计有18种&#xff0c;按照类别可…

CentOS7安装Redis集群

本章是基于CentOS7下的Redis集群 1.单机安装Redis2.Redis主从集群2.1.集群结构2.2.准备实例和配置2.3.启动2.4.开启主从关系2.5.测试 3.搭建哨兵集群3.1.集群结构3.2.准备实例和配置3.3.启动3.4.测试 4.搭建分片集群4.1.集群结构4.2.准备实例和配置4.3.启动4.4.创建集群4.5.测试…

听听Dreamforce ‘23中Salesforce高管们对产品、功能的见解!

True to the Core是Dreamforce的传统环节&#xff0c;这是向Salesforce高级管理人员提出问题的问答会议。True to the Core旨在将Trailblazer与产品团队联系起来&#xff0c;做出有关产品发展方向的决策。 Dreamforce 23 的True to the Core没有令人失望&#xff0c;提供了关…

代码覆盖率统计Super-jacoco在公司级容器化项目中的具体应用方案

目录 一、介绍 二、自己在本地搭建Super-jacoco服务 2.1 准备工作 2.2 部署super jacoco服务 1、下载super jacoco 项目 2、初始化数据库 3、配置application.properties 4、编译super jacoco项目 5、部署 super jacoco 服务 2.3 启动被测项目 2.4、代码覆盖率收集 2…

(3) OpenCV图像处理kNN近邻算法-识别摄像头数字

目录 一、代码简介 二、程序代码 三、使用的图片资源 1、图片digits.png

为什么价格监测要精确到款式

品牌在进行线上数据的监测时&#xff0c;首先需要对全网数据进行爬取&#xff0c;爬到的数据再做分析&#xff0c;最后再对有效的SKU数据进行监测&#xff0c;所以数据清洗很重要&#xff0c;采集到的基础数据更重要&#xff0c;只有数据采集全面了&#xff0c;才能进行全面的控…

python——loguru第三方日志管理模块

loguru第三方日志管理模块 loguru介绍日志等级日志保存日志过滤处理异常 loguru介绍 loguru是第三方库&#xff0c;拿来即用&#xff0c;不用太多的配置 安装&#xff1a;pip install loguru 日志等级 from loguru import loggerlogger.debug(这是一条调试消息&#xff01;)…

E054-web安全应用-Brute force暴力破解进阶

课程名称&#xff1a; E054-web安全应用-Brute force暴力破解进阶 课程分类&#xff1a; web安全应用 实验等级: 中级 任务场景: 【任务场景】 小王接到磐石公司的邀请&#xff0c;对该公司旗下的网站进行安全检测&#xff0c;经过一番检查发现该网站可能存在弱口令漏洞…

【Java笔试强训】Day1(100449-组队竞赛 、OR63 删除公共字符)

100449-组队竞赛 链接&#xff1a;组队竞赛 题目&#xff1a; 牛牛举办了一次编程比赛,参加比赛的有3*n个选手,每个选手都有一个水平值a_i.现在要将这些选手进行组队,一共组成n个队伍,即每个队伍3人.牛牛发现队伍的水平值等于该队伍队员中第二高水平值。 例如: 一个队伍三个…

修改ruoyi框架前端刷新页面时紫色的背景颜色

问题描述 最近在使用ruoyi的前后端分离框架&#xff0c;发现前端VUE页面刷新的时候&#xff0c;会出现加载的紫色页面&#xff0c;想要修改这个颜色&#xff0c;请看下面的教程。 修改教程 找到public/index.html&#xff0c;然后找到background为#7171C6这个颜色的代码&…

Redis 主从复制,哨兵,集群——(2)哨兵篇

目录 1. Redis 哨兵是什么&#xff1f; 2. Redis 哨兵有什么用&#xff1f; 2.1 主动监控 2.2 消息通知 2.3 故障转移 2.4 配置中心 3. Redis 哨兵数量配备要求 4. 哨兵配置文件详解 5. quorum 投票数详解 5.1 quorum 的含义 5.2 网络抖动导致主观下线 5.3 quorum …

Spring framework Day21:Spring AOP 注解结合配置类示例

前言 Spring AOP是一种强大的面向切面编程工具&#xff0c;它能够帮助我们更好地处理与核心业务逻辑无关的横切关注点。通过使用注解和配置类的方式&#xff0c;我们可以更加简洁和灵活地实现AOP。 本文将以一个示例来介绍如何结合注解和配置类来使用Spring AOP。通过这个示例…

解决Antd 二次封装表格的可编辑功能(editable table)不生效的问题

问题概述 使用了Antd Table组件&#xff0c;因为需要自定义的筛选功能&#xff0c;进行了二次封装。 之后加上了可编辑行功能&#xff0c;当点击编辑图标&#xff0c;发现表格并不会有任何变化。 代码&#xff1a; <Formcomponent{false}form{docInfoForm} ><CSTab…

正点原子嵌入式linux驱动开发——设备树下LED驱动

经过对设备树的学习以及驱动开发中常用的OF函数介绍&#xff0c;本篇笔记将之前的新字符设备驱动的LED&#xff0c;换成设备树形式。 设备树LED驱动原理 在之前的新字符设备驱动实验中&#xff0c;直接在驱动文件newchrled.c中定义有关寄存器物理地址&#xff0c;然后使用io_…

【前端学习】—Vue生命周期(十七)

【前端学习】—Vue生命周期&#xff08;十七&#xff09; 一、Vue生命周期 二、Vue父子组件生命周期调用顺序 三、Vue中在哪个生命周期内调用异步请求

【SpringCloud微服务项目实战-mall4cloud项目(4)】——mall4cloud-rbac

mall4cloud-rbac角色权限访问控制模块 系统架构与模块介绍系统架构rbac模型介绍 相关代码权限校验接口代码 补充 代码地址 github地址 fork自github原始项目 gitee地址 fork自gitee原始项目 系统架构与模块介绍 系统架构 从图中可以看到&#xff0c;微服务集群中&#xff0c;…

Netty系列教程之NIO基础知识

近30集的孙哥视频课程&#xff0c;看完一集整理一集来的&#xff0c;内容有点多&#xff0c;请大家放心食用~ 1. 网络通讯的演变 1.1 多线程版网络通讯 在传统的开发模式中&#xff0c;客户端发起一个 HTTP 请求的过程就是建立一个 socket 通信的过程&#xff0c;服务端在建立…

直线导轨在喷涂行业中的应用场景

直线导轨因其具有精度高、速度快、刚性强、使用寿命长等特点被广泛应用在各行各种中&#xff0c;其中&#xff0c;在喷涂行业中的应用最为广泛&#xff0c;以下是直线导轨在喷涂行业中的应用场景&#xff1a; 1、平面喷涂&#xff1a;直线导轨可以应用在各种机械加工的平面&…