浅析declval关键字

news2024/11/17 23:43:48

浅析 declval 关键字

文章目录

  • 浅析 declval 关键字
    • 前言
    • declval 的基本概念
    • declval 的工作原理
    • declval 的实际应用案例
    • 总结

前言

​ 在现代C++编程中,std::declval是一个非常有用的工具,它允许我们在不实例化对象的情况下使用其类型。这在模板元编程中尤其重要,因为它使得我们能够在编译时进行类型推导,而无需关心对象的构造。std::declval的引入极大地增强了C++的表达能力,使得编写通用代码和库变得更加灵活和强大。


declval 的基本概念

std::declval是一个模板函数,它可以将任何类型T转换为右值引用T&&。这个函数主要用于decltype表达式中,以便在不实例化对象的情况下推导成员函数的返回类型。

说到底 declval 到底能干什么?它就是用于返回一个 T 对象的伪造实例,同时又具有右值引用参考。换句话说,它等价于下面的 objref 的编译期态:

T obj{};
T &objref = obj{};

首先,它在词法和语义上等价于 objref,是对象 T 的实例值,且具有 T&& 的类型;其次,它仅用于非求值的场合;再次,它并不真的存在。

说人话就是在编译期中,需要一个值对象,但并不希望这个值对象被编译为一个二进制实体,那就用 declval 虚拟地构造一个,从而彷佛获得了一个临时对象,可以在该对象上施加操作,例如调用成员函数什么的,但既然是虚拟的,就不会真的存在这么个临时对象,所以我称之为伪实例。

例如,如果你想知道某个类Foo的成员函数bar的返回类型,你可以这样写:

decltype(std::declval<Foo>().bar())

这行代码不会创建Foo的实例,也不会调用bar函数,它只是用于类型推导

declval 的工作原理

具体来说,std::declval的实现通常如下所示:

template<class T>
typename std::add_rvalue_reference<T>::type declval() noexcept;

这个函数模板会将类型T转换为右值引用T&&。这里的std::add_rvalue_reference是一个类型特性,它会给T添加一个右值引用。如果T已经是一个引用类型,那么根据C++的引用折叠规则,结果仍然是一个合法的引用类型。

这种设计使得std::declval可以在编译时期进行类型推导,而无需担心对象的构造和初始化,这对于模板编程和泛型编程来说非常有用。

declval 的实际应用案例

在未求值上下文中的应用

未求值上下文是指表达式的类型被计算,但表达式本身并不被执行

std::declval只能在未求值的上下文中使用,比如decltypesizeof表达式。在这些上下文中,表达式的类型被计算,但表达式本身并不被执行。因此,即使std::declval看似返回了一个对象的引用,实际上并没有创建对象实例,也没有调用任何函数。

下图很好的总结了 declval 的适用场景和案例:

在这里插入图片描述

与 decltype 配合

#include <iostream>

namespace {
  struct base_t { virtual ~base_t(){} };

  template<class T>
    struct Base : public base_t {
      virtual T t() = 0;
    };

  template<class T>
    struct A : public Base<T> {
      ~A(){}
      virtual T t() override { std::cout << "A" << '\n'; return T{}; }
    };
}

int main() {
  decltype(std::declval<A<int>>().t()) a{}; // = int a;
  decltype(std::declval<Base<int>>().t()) b{}; // = int b;
  std::cout << a << ',' << b << '\n';
}

可以看到,A<int> 的伪实例能够“调用” A 的成员函数 t(),然后借助于 decltype 我们就可以拿到 t() 的返回类型,并用来声明一个具体的变量 a。

无默认构造函数

如果一个类没有定义默认构造函数,在元编程环境中可能是很麻烦的。例如下面的 decltype 就无法通过编译:

struct A{
  A() = delete;
  int t(){ return 1; }
}

int main(){
  decltype(A().t()) i; // 编译报错
}

因为 A() 是不存在的。

但改用 declval 就能够绕过问题了:

int main(){
  decltype(std::declval<A>().t()) i; // OK
}

纯虚类

在纯虚基类上有时候元编程会比较麻烦,这时候可能可以借助 declval 来避开纯虚基类不能实例化的问题。

struct base_t { virtual ~base_t(){} };

template<class T>
struct Base : public base_t
{
    virtual T t() = 0;
};

int main() 
{
  decltype(std::declval<Base<int>>().t()) b{};	// 注意这里获得了抽象类的成员函数返回值类型
}

总结

​ 通过本文的探讨,我们对std::declval有了更深入的理解。它不仅是模板元编程的重要工具,也是现代C++中不可或缺的一部分。虽然std::declval只能在未求值的上下文中使用,但它在类型推导和模板编程中发挥着关键作用。

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

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

相关文章

OpenAI 与 Reddit 达成重要合作伙伴关系

Reddit是一个娱乐、社交及新闻网站&#xff0c;注册用户可以将文字或链接在网站上发布&#xff0c;使它基本上成为了一个电子布告栏系统。注册用户可以对这些帖子进行投票&#xff0c;结果将被用来进行排名和决定它在首页或子页的位置。网站上的内容分类被称为“subreddit”。s…

Vue3实战笔记(39)—封装页脚组件,附源码

文章目录 前言一、封装页脚组件二、使用组件总结 前言 在Web开发中&#xff0c;页脚组件是一个重要的部分&#xff0c;它为用户提供关于网站的信息、导航链接以及版权声明等。而封装页脚组件则是一种高效的方法&#xff0c;可以提高代码的可重用性和可维护性。 一、封装页脚组…

4.2 循环语句(for, while)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

高中数学:平面向量-正交分解、坐标表示、坐标运算

一、正交分解 二、坐标表示 这里注意一点 坐标A(x,y)与向量 a → \mathop{a}\limits ^{\rightarrow} a→的坐标记作&#xff1a; a → \mathop{a}\limits ^{\rightarrow} a→(x,y)&#xff0c;表示方式的区别 引申 三、加减运算的坐标表示 四、数乘运算的坐标表示 引申 两向量…

爬虫学习--12.MySQL数据库的基本操作(下)

MySQL查询数据 MySQL 数据库使用SQL SELECT语句来查询数据。 语法&#xff1a;在MySQL数据库中查询数据通用的 SELECT 语法 SELECT 字段1&#xff0c;字段2&#xff0c;……&#xff0c;字段n FROM table_name [WHERE 条件] [LIMIT N] 查询语句中你可以使用一个或者多个表&…

golang创建式设计模式---工厂模式

创建式设计模式—工厂模式 目录导航 创建式设计模式---工厂模式1)什么是工厂模式2)使用场景3)实现方式4)实践案例5)优缺点分析 1)什么是工厂模式 工厂模式(Factory Method Pattern)是一种设计模式&#xff0c;旨在创建对象时&#xff0c;将对象的创建与使用进行分离。通过定义…

GPIO模拟IIC通信测量环境光

目录 iic.h iic.c ap3216c.h ap3216.c main.c 实验效果 iic.h #ifndef __IIC_H__ #define __IIC_H__#include "stm32mp1xx_gpio.h" #include "stm32mp1xx_rcc.h" //SDA 数据线为PF15 //SCL 时钟线为PF14//配置PF15为输出模式 #define SET_SDA_OUT d…

六.逼格拉满-Prometheus+Grafana微服务监控告警

前言 微服务架构是一个分布式系统&#xff0c;由多个独立的服务组成&#xff0c;每个服务可能运行在不同的容器、虚拟机或物理机上&#xff0c;那么在生产环境中我们需要随时监控服务的状态&#xff0c;以应对各种突发情况&#xff0c;比如&#xff1a;内存爆满&#xff0c;CP…

个人如何利用AI大模型工具搞钱

人工智能&#xff08;AI&#xff09;技术的迅速发展&#xff0c;使得许多以前难以想象的应用场景变得可能。尤其是AI大模型&#xff08;如GPT-4&#xff09;在自然语言处理、图像识别等方面表现出色&#xff0c;为个人带来了许多新的赚钱机会。本文将详细介绍几种个人如何利用A…

无接口文档快速模拟接口请求-postman 3步搞定;

一&#xff1a;接口&#xff1a;鼠标右键复制&#xff1a;以curl&#xff08;bash&#xff09;格式复制&#xff1a; 二&#xff1a;然后拷贝到postman黏贴的方式&#xff1a; 打开 postman &#xff0c; 点击左上角的 Import &#xff0c; 选择 Raw Text &#xff0c;黏贴后…

计算机毕业设计 | springboot+vue汽车修理管理系统 汽修厂系统(附源码)

1&#xff0c;项目背景 在如今这个信息时代&#xff0c;“汽车维修管理系统” 这种维修方式已经为越来越多的人所接受。在这种背景之下&#xff0c;一个安全稳定并且强大的网络预约平台不可或缺&#xff0c;在这种成熟的市场需求的推动下&#xff0c;在先进的信息技术的支持下…

纯血鸿蒙APP实战开发——边缓存边播放案例

介绍 OhosVideoCache是一个支持边播放边缓存的库&#xff0c;只需要将音视频的url传递给OhosVideoCache处理之后再设置给播放器&#xff0c; OhosVideoCache就可以一边下载音视频数据并保存在本地&#xff0c;一边读取本地缓存返回给播放器&#xff0c;使用者无需进行其他操作…

函数的MC/DC代码覆盖率

函数的MC/DC&#xff08;Modified Condition/Decision Coverage&#xff09;代码覆盖率是一种软件测试覆盖率指标&#xff0c;它特别关注于在决策&#xff08;如if-else语句&#xff09;中条件和决策本身的测试。MC/DC 覆盖率旨在确保每个条件在决策中至少被评估为真和假一次&a…

iptables+SNAT+DNAT

一、Linux包过滤防火墙概述 主要工作在网络层&#xff0c;针对IP数据包&#xff0c;体现在对包内的IP地址、端口、协议等信息的处理上 以下两种称呼都可以表示Linux防火墙 netfilter 位于Linux内核中的包过滤功能体系 成为Linux防火墙的“内核态” 是内核的一部分&#xff0…

如何远程连接默认端口?

远程连接是指通过网络实现两个或多个计算机之间的连接和通信。在进行远程连接时&#xff0c;使用的端口号是一个重要的参数。端口号是计算机上正在运行的特定应用程序的标识符。每个应用程序都会监听一个或多个特定的端口号&#xff0c;以便接收来自其他计算机的连接请求&#…

按照行业划分,蓝牙模块怎么选型?

蓝牙模块是一种将外围硬件电路和芯片集成到一个PCBA板上&#xff0c;通过相关IO串口和MCU控制设备&#xff0c;进行数据信息传输、蓝牙通信和组网功能&#xff0c;达到短距离无线通讯目的&#xff0c;实现电子产品所需的内置程序蓝牙功能的设备。 今天美迅物联网MesoonRF主要教…

K8S认证|CKA题库+答案| 14. 排查故障节点

14、排查集群中的故障节点 您必须在以下Cluster/Node上完成此考题&#xff1a; Cluster Master node Worker node wk8s master …

Android JetPack ViewModel

一、什么是ViewModel&#xff1f; Android ViewModel在我们使用MVVM开发模式时会经常用到&#xff0c;对我来说就是好用&#xff0c;好维护。 它相对于MVC模式&#xff0c; 一来可以减少Activity层的代码&#xff0c;可以把一些业务逻辑和对数据的交互到ViewModel层去&#…

民国漫画杂志《时代漫画》第14期.PDF

时代漫画14.PDF: https://url03.ctfile.com/f/1779803-1247458399-6732ac?p9586 (访问密码: 9586) 《时代漫画》的杂志在1934年诞生了&#xff0c;截止1937年6月战争来临被迫停刊共发行了39期。 ps:资源来源网络&#xff01;

vue 微信小程序 uniapp 微信头像上传裁剪功能

效果如图&#xff1a; 操作流程&#xff1a; 个人中心–点击设置头像–选择图片-裁剪–选取–上传 template <view class"meilan" style"position: relative;"><u-row justify"space-between"><u-col span"3">设置头…