惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 三生石上(FineUI控件)
Hugging Face - Blog
Hugging Face - Blog
M
MIT News - Artificial intelligence
T
Tailwind CSS Blog
Webroot Blog
Webroot Blog
S
Secure Thoughts
N
News and Events Feed by Topic
月光博客
月光博客
TaoSecurity Blog
TaoSecurity Blog
Microsoft Azure Blog
Microsoft Azure Blog
B
Blog RSS Feed
N
News | PayPal Newsroom
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
小众软件
小众软件
Recent Commits to openclaw:main
Recent Commits to openclaw:main
P
Privacy & Cybersecurity Law Blog
GbyAI
GbyAI
K
Kaspersky official blog
WordPress大学
WordPress大学
P
Proofpoint News Feed
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
博客园 - 叶小钗
W
WeLiveSecurity
Jina AI
Jina AI
The Cloudflare Blog
Project Zero
Project Zero
Simon Willison's Weblog
Simon Willison's Weblog
V
Vulnerabilities – Threatpost
L
LangChain Blog
Forbes - Security
Forbes - Security
PCI Perspectives
PCI Perspectives
Engineering at Meta
Engineering at Meta
Google DeepMind News
Google DeepMind News
Recorded Future
Recorded Future
博客园 - 【当耐特】
H
Heimdal Security Blog
A
About on SuperTechFans
Cisco Talos Blog
Cisco Talos Blog
T
Threat Research - Cisco Blogs
云风的 BLOG
云风的 BLOG
Spread Privacy
Spread Privacy
L
LINUX DO - 最新话题
L
Lohrmann on Cybersecurity
Last Week in AI
Last Week in AI
Google DeepMind News
Google DeepMind News
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
I
Intezer
Martin Fowler
Martin Fowler
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint

音视频开发进阶

音视频教程-第三节 音视频教程-第二节 真的,AI 可能就是新时代的信息差 充值 Cursor 之后,工作有了哪些变化?🤔 个人'蒸馏'大模型能做哪些有意思的事情 DeepSeek 大模型在 Mac 上的部署和运行 音视频教程-第一节 【WebRTC 专栏】-- Android 开发集成 WebRTC 库的几种方式 【WebRTC 专栏】-- 在 Mac M1 等系列芯片编译和开发 WebRTC-Android 库 Meta Llama3 大模型在 Mac 上的部署和运行 iOS VideoToolBox 解码 HEVC Open-GOP 视频的问题排查 Flutter 状态管理之 InheritedWidget 使用和分析 用 ChatGPT 回答技术问题怎么样 ? 音视频开发系统入门大致路线 UE 4.27 添加自定义 ShadingModel 用 UE4 虚幻引擎做个捏脸小功能~~ UE4 材质练习 之 凹凸贴图偏移的使用 UE4 材质练习系列基础 OpenGL上下文创建以及共享机制 007 | 播放器系列专栏-解析 MP4 文件读取信息 006 | 播放器系列专栏-在 Mac 上查看 MP4 格式信息 干货 | 快速抽取缩略图是怎么练成的? 关于直播、WebRTC、FFmpeg 的那些事 005 | 播放器系列专栏-在 Windows 上查看 MP4 格式信息 将音视频中的花屏、绿屏、黑屏问题一网打尽 关于音视频里面的解码帧率和渲染帧率 004 | 播放器系列专栏-认识MP4视频(下) 003 | 播放器系列专栏-认识MP4视频(上) 入门或者转行音视频,应该要怎么做? H264视频文件如何缩放分辨率 002 | 播放器系列专栏-FFmpeg依赖库的配置 001 | 播放器系列专栏-关于播放器项目的一个小实践 Seek策略以及在有B帧情况下的处理 目前流媒体开发工程师工作内容主要是什么? 一个音视频领域专业问答的小圈子 干货收藏 || Vulkan Game Engine 视频教程 音视频春节假期内卷指南(实操) Vulkan 在 FFmpeg 中的支持 Windows 下 FFmpeg 和 LibX264 的编译和配置 Metal 开发 | 使用 C++ 进行接口调用 音视频开发工作经验分享 || 视频版 FFmpeg 调用 MediaCodec 硬解码到 Surface 上 代码吸猫 | 用 OpenGL 图像渲染的养猫计划 百倍变速--解码到底能不能丢 非参考帧 ?FFmpeg 有话说!!! 老生常谈-FFmpeg 的编译问题轻松搞定 FFmpeg 调用 Android MediaCodec 进行硬解码(附源码) 【WebRTC 专栏】--创建相机预览 Unity Shader 光照基础之 Half Lambert 光照模型 Unity Shader 光照基础之Lambert光照模型 Unity Shader 光照基础内容 Unity Shader 显示一张图片纹理 UnityShader 的基本概念 Unity 物体的基本操作 C++ 模板系列小结06-可变参数模板特性 C++ 中的多线程的使用和线程池建设 C++ 模板系列小结05-模板类型作为模板参数 C++ 模板系列小结04-类模板中的成员模板 C++ 模板系列小结03-在模板中指定变量类型 C++ 模板系列小结02-非类型模板参数 C++ 模板系列小结01-函数模板和类模板 从零打造渲染引擎系列01-什么是渲染引擎 iOS开发 - 在 Swift 中去调用 C/C++ 代码 2021 技术新番 - 从零打造渲染引擎系列 iOS 音视频开发的一些基础准备工作 音视频交流群又来啦~~~ 【WebRTC 专栏】WebRTC & Android 开发学习环境搭建~ 【喜大普奔】域名终于备案通过啦 Shader 优化 | OpenGL 绘制网格效果 【音视频连载-011】第二季 FFmpeg 一层一层获取文件信息 KodeLife | Shader 实时编辑预览的强大工具使用实践 推荐几个堪称教科书级别的 Android 音视频入门项目 【音视频连载-010】第二季 FFmpeg 日志打印 【音视频连载-008】基础学习篇-SDL 播放 PCM 音频文件(下) 【音视频连载-007】基础学习篇-SDL 播放 PCM 音频文件(上) 【音视频连载-006】基础学习篇-SDL 播放 YUV 视频文件 【音视频连载-005】基础学习篇-SDL 加载 YUV 文件并显示 【音视频连载-004】基础学习篇-SDL 加载图片并显示 【音视频连载-003】基础学习篇-SDL 消息循环和事件响应 【音视频连载-002】基础学习篇-SDL 创建窗口并显示颜色 【音视频连载-001】基础学习篇- SDL 介绍以及工程配置 LearnOpenGL 源码在 MAC 上的编译与调试 2019 年终总结与回顾 Android NDK 开发的免费技术视频来啦~~ OpenGL 实现视频编辑中的转场效果 OpenGL 实践之贝塞尔曲线绘制 图像库 libjpeg-turbo 编译与实践 图像库 libpng 编译与实践 rust 开发编译 Android 动态库实践 Android NDK 开发 —— 从 Assets 文件夹加载图片并上传纹理 简单易用的图像解码库介绍 —— stb_image 博客图床迁移记 进击的 Vulkan 移动开发之 SwapChain 进击的 Vulkan 移动开发之 Command Buffer 进击的 Vulkan 移动开发之 Instance & Device & Queue 进击的 Vulkan 移动开发(一)之今生前世 Java 显式锁 Lock 与条件队列 C++ 标准容器库小结 MediaCodec 硬编码之相机内容编码成 H264 文件 一文读懂 YUV 的采样与格式 《OpenGL ES 3.x 游戏开发》碰撞检测之 AABB 包围盒
C++ 模板系列小结07-尾置返回类型
音视频开发进阶 · 2021-02-20 · via 音视频开发进阶

一个专注音视频领域的小圈子

在使用模板时可以显示指定模板类型,尤其是针对有返回类型的模板,显示指定可以避免类型转换带来的困扰。 但有时候显示指定模板实参类型会给用户增添额外负担,而且不会带来什么好处。 比如如下代码,接受表示序列的一对迭代器和返回序列中的一个元素的引用:

template<typename It>
??? &fcn(It beg,It end){
    return *beg;
}

我们并不知道返回结果的准确类型,但知道所需类型是所处理的序列的元素类型。

vector<int> vi = {1,2,3,4,5};
auto &i =fcn(vi.begin,vi.end());

如上代码,知道函数应该返回 *beg,而且知道我们可以用 decltype(*beg) 来获取此表达式的类型。 但是,在编译器遇到函数的参数列表之前,beg 都是不存在的。为此,我们需要使用尾置返回类型。 由于尾置返回出现在参数列表之后,它可以使用函数的参数:

// 尾置返回允许在参数列表之后声明返回类型
template<typename It>
auto fcn(It beg,It end) -> decltype(*beg){
    return *beg;
}

在上面的例子中,fcn 的返回类型和解引用 beg 参数的结果类型相同。

解引用运算符返回一个左值,因此通过 decltype 推断的类型为 beg 表示的元素的类型的引用。

比如,如果对一个 string 序列调用 fcn,返回类型是 string& ,如果是 int 序列,返回类型是 int& 。

关于为何返回的类型是引用类型,可以回顾一下 decltype 的使用:

decltype 的使用

当希望从表达式的类型推断出要定义的变量的类型,但是不想用该表达式的值初始化变量。为了满足这一要求,C++11 新标准引入了类型说明符 decltype ,它的作用是选择并返回操作数的数据类型。

在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。

int f(){
    return 1;
}

int main(){
    int x = 2;
    decltype(f()) sum = x;
    return 0;
}

如上代码所示,编译器并不实际调用函数 f ,而是使用当调用发生时 f 的返回值类型作为 sum 的类型。换句话说,编译器为 sum 指定的类型就是 f 被调用时返回的那个类型。

如果 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;             // z 是一个引用,必须初始化

如果 decltype 返回的变量类型是一个引用,那么对应的变量就必须初始化才行。

另外,如果 decltype 使用的表达式不是一个变量,则 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 ,显然这个表达式的结果将是一个具体指而非一个引用。

另外,如果一个表达式的内容是解引用操作,则 decltype 将得到引用类型。因为,解引用指针可以得到指针所指的对象,而且还能给这个对象赋值。因此,decltype(*p) 的结果就是 int& ,而非 int 。

另外,对于 decltype 所用的表达式来说,如果变量名加上了一对括号,则得到的类型与不加括号时会有不同。

如果 decltype 使用的是一个不加括号的变量,则得到的结果就是该变量的类型。如果给变量加上了一层或多层括号,编译器会把它当成一个表达式,而变量是一种可以作为赋值语句左值的特殊表达式,这是 decltype 就会得到引用类型。

decltype((i)) d;  // 错误,d 是引用类型, int& ,必须要初始化
decltype(i) e;      //正确,e 是未初始化的 int 

尾置返回元素为值而非引用

在前面的例子中,返回的是引用类型,但是有时候希望返回一个元素的值,而非引用。

template<typename It>
auto fcn(It beg,It end) -> decltype(*beg){
    return *beg;
}

但问题在于,无法知道传递的参数类型,唯一可以使用的操作是迭代器操作,而所有迭代器操作都不会生成元素,只能生成元素的引用。

为了获得元素类型,要使用标准库的类型转换模板

这些模板定义在头文件 type_traits 中,主要是用于模板元编程设计的,这次主要用到 remove_reference 模板,它的源码如下:

template <class _Tp> struct _LIBCPP_TEMPLATE_VIS remove_reference        {typedef _LIBCPP_NODEBUG_TYPE _Tp type;};

如同它的名字一样,就是移除引用,可以通过它来获得元素类型。remove_reference 模板有一个模板类型参数和一个名为 type 的类型成员。

如果用一个引用类型实例化 remove_reference,则 type 将表示被引用的类型。

例如,实例化 remove_reference<int&> ,则 type 成员将是 int 。类似,如果实例化 remove_reference<string&> ,则 type 成员将是 string 。

如果给定一个迭代器 beg:

remove_reference<decltype(*beg)>::type

将获得 beg 引用的元素的类型:decltype(*beg) 返回元素类型的引用类型,remove_reference::type 脱去引用,剩下元素类型本身。

组合使用 remove_reference、尾置返回以及 decltype ,就可以在函数中返回元素值的拷贝。

template<typename It>
auto fcn2(It beg,It end) -> typename remove_reference<decltype(*beg)>::type{
    return *beg; // 返回序列中一个元素的拷贝
}

要注意的是,type 是一个类的成员,而该类依赖于一个模板参数。因此,要在返回类型的声明中使用 typename 来告知编译器,type 表示一个类型,关于这个知识点在之前的文章中提到过了,参见:C++ 模板系列小结03-在模板中指定变量类型

小结

尾置返回类型主要还是 decltype 的使用了,而 decltype 要注意的是返回的类型是元素的类型,还是引用类型了,在不同场景下注意区分。

原创文章,转载请注明来源:    C++ 模板系列小结07-尾置返回类型