跟我学c++中级篇——注解

news/2024/11/26 21:27:50/

一、注解是什么

其实中这里分析注解的原因是和反射有些关系的,当然实现注解的手段可能有很多种,但一般来说,注解实现都和反射或多或少有着关系。那么什么是注解?注解就是对类或方法等的元数据描述。所以注解就是一种元数据,它是一种对代码的特殊标记。
注解可以有两种方式来应用,一种是在编译期进行扫描;另外一个是在运行期使用反射的方式来获取相关的注解信息。所以从这两点来分析,c++目前来看,只能在编译期进行注解的处理。在运行期利用反射,至少标准目前还不支持,都是一些框架自己实现的。

二、c++11以上的注解

在早期的c++标准中,对注解可以说是没有支持的必要。毕竟玩儿c++的可都不是一般的程序员,但再高大上的东西,总有一天要“飞入寻常百姓家”,而且注解这个东西确实是对开发者有着不小的作用,所以从c++11开始,注解就慢慢上来了。不过在c++中可能不叫注解,叫属性(Attribute)。

Syntax
[[ attribute-list ]]		(since C++11)
[[ using attribute-namespace : attribute-list ]]		(since C++17)
where attribute-list is a comma-separated sequence of zero or more attributes (possibly ending with an ellipsis ... indicating a pack expansion)identifier	(1)
attribute-namespace :: identifier	(2)
identifier ( argument-list )	(3)
attribute-namespace :: identifier ( argument-list )	(4)
1) Simple attribute, such as [[noreturn]].
2) Attribute with a namespace, such as [[gnu::unused]].
3) Attribute with arguments, such as [[deprecated("because")]].
4) Attribute with both a namespace and an argument list.

其实在早期的开发者中,也可以看到一些编译器厂商自己增加的属性,如GNU 的语言扩展 _attribute_((…)),微软的语言扩展 __declspec() 等,一般情况下,属性可以应用于c++中所有的位置,包括类型、变量、函数、代码块甚至整个单元等等。不过这里强调的注解可能更货币于函数和类型。也就是类似于:

[[attribute]] types/functions

在c++11以后定义了下列几个标准的属性:

C++ 标准仅定义下列属性。[[noreturn]](C++11 起)	指示函数不返回
[[carries_dependency]](C++11 起)	指示释放消费 std::memory_order 中的依赖链传入和传出该函数。
[[deprecated]](C++14 起)
[[deprecated("原因")]](C++14 起)	指示允许使用声明有此属性的名称或实体,但因 原因 而不鼓励使用。
[[fallthrough]](C++17 起)	指示从前一 case 标号直落是有意的,而在发生直落时给出警告的编译器不应该为此诊断。
[[nodiscard]](C++17 起)
[[nodiscard("原因")]](C++20 起)	鼓励编译器在返回值被舍弃时发布警告。
[[maybe_unused]](C++17 起)	压制编译器在未使用实体上的警告,若存在。
[[likely]](C++20 起)
[[unlikely]](C++20 起)	指示编译器应该针对通过某语句的执行路径比任何其他执行路径更可能或更不可能的情况进行优化。
[[no_unique_address]](C++20 起)	指示非静态数据成员不需要拥有不同于其类的所有其他非静态数据成员的地址。
[[assume]](C++23 起)	指出某个表达式在某个地方始终会求值为 true。
[[optimize_for_synchronized]](TM TS)	指示应该针对来自 synchronized 语句的调用来优化该函数定义

对于支持自定义属性,目前标准还是比较模糊,反正c++有一条,如果不合适,结果就是未知,自己考虑清楚即可。

三、例程

先看几个cppreference上的例程:

[[ noreturn ]] void f() {throw "error";// OK
}void q [[ noreturn ]] (int i) {// 若以 <= 0 的参数调用则行为未定义if (i > 0) {throw "positive";}
}// void h() [[noreturn]]; // 错误:属性应用到 h 的函数类型,而非 h 自身

象一些系统调用的API函数,都可以增加这个属性来防止未知情况。

#include <iostream>[[deprecated]]
void TriassicPeriod() {std::clog << "Triassic Period: [251.9 - 208.5] million years ago.\n";
}[[deprecated("Use NeogenePeriod() instead.")]]
void JurassicPeriod() {std::clog << "Jurassic Period: [201.3 - 152.1] million years ago.\n";
}[[deprecated("Use calcSomethingDifferently(int).")]]    
int calcSomething(int x) {return x * 2;
}int main()
{TriassicPeriod();JurassicPeriod();
}

再看一个前面曾经提到过的:

#include <iostream>int f(int i)
{if (i < 0) [[unlikely]] {return 0;}return 1;
}int main()
{std::cout << f(-1) << std::endl;std::cout << f(1) << std::endl;
}

最后再看一个常用的:

void f(int n)
{void g(), h(), i();switch (n){case 1:case 2:g();[[fallthrough]];case 3: // 直落时不警告h();case 4: // 编译器可在发生直落时警告if (n < 3){i();[[fallthrough]]; // OK}else{return;}case 5:while (false){[[fallthrough]]; // 非良构:下一语句不是同一迭代的一部分}case 6:[[fallthrough]]; // 非良构:没有后继的 case 或 default 标号}
}

其实很多小的技术细节,往往会被开发者忽略,但当某个时刻看到某些人应用的非常巧妙时,又击节叹服。其实这说白了还是对整个体系掌握的不够深入,等深入掌握了,某些细节其实就是习惯的事情了。

四、总结

其实谈注解并没有多少太多的新奇的技术,在其它高级语言,特别是搞Java的同学中,这个太多了,现在几乎是普遍了。所以c++也在跟进,好的东西,其实是普遍受欢迎的,正如美是没有国界的。但c++固有的属性使其的发展不可能一下子就对注解之类的技术支持非常完美。但是只要开了头,后面就会越来越好。
这里把这个注解拿出来,就是和反射在一起分析,让大家有一个更深刻的认识。对开发者来说简单的事情,可能对底层开发支持人员,就是一个新技术的应用。每个次语言标准的进步,其实就是很多基础开发人员的努力,希望有一天,我们也能坐到这个位置,为普通开发者,提供技术支持。


http://www.ppmy.cn/news/97366.html

相关文章

网络编程(TCP与UDP协议)

文章目录 1. 网络编程1.1 软件架构1.2 网络基础 2. 网络通信要素2.1 如何实现网络中的主机互相通信2.2 通信要素一&#xff1a;IP地址和域名2.2.1 IP地址2.2.2 域名 2.3 通信要素二&#xff1a;端口号2.4 通信要素三&#xff1a;网络通信协议 3. 传输层协议&#xff1a;TCP与UD…

【STL】list的模拟实现

目录 前言 结构解析 默认成员函数 构造函数 拷贝构造 赋值重载 析构函数 迭代器 const迭代器 数据修改 insert erase 尾插尾删头插头删 容量查询 源码 前言 &#x1f349;list之所以摆脱了单链表尾插麻烦&#xff0c;只能单向访问等缺点&#xff0c;正是因为其…

电子器件系列38:mos管散热片

板子上需要用到一个封装为to220的mos管&#xff0c;还得立起来散热&#xff0c;得要加一个散热片。 散热片简介&#xff0c;分类&#xff1f;用途&#xff1f;如何使用&#xff1f;封装&#xff1f;使用注意事项&#xff1f; 简介&#xff1a; mos散热片是一种给电器中的易发热…

VSLAM视觉里程计总结

相机模型是理解视觉里程计之前的基础。视觉里程计&#xff08;VIO&#xff09;主要分为特征法和直接法。如果说特征点法关注的是像素的位置差&#xff0c;那么&#xff0c;直接法关注的则是像素的颜色差。特征点法通常会把图像抽象成特征点的集合&#xff0c;然后去缩小特征点之…

Radxa ROCK 5A RK3588S 开箱 vs 树莓派

Rock5 Model A 是一款高性能的单板计算机&#xff0c;采用了 RK3588S (8nm LP 制程&#xff09;处理器&#xff0c;具有 4 个高达 2.4GHz 的 ARM Cortex-A76 CPU 核心、4 个高达 1.8GHz 的 Cortex-A55 内核和 Mali-G610 MP4 GPU&#xff0c;支持 8K 60fps 视频播放&#xff0c…

Oracle数据库表空间数据删除以及数据库重启

-删除空的表空间&#xff0c;但是不包含物理文件 drop tablespace tablespace_name; –删除非空表空间&#xff0c;但是不包含物理文件 drop tablespace tablespace_name including contents; –删除空表空间&#xff0c;包含物理文件 drop tablespace tablespace_name includi…

初识linux之简单了解TCP协议与UDP协议

目录 一、理解源IP地址和目的IP地址 二、端口号 1. 为什么要有端口号 2. 理解端口号 3. 源端口号和目的端口号 三、初步了解TCP协议和UDP协议 1. 初步认识TCP协议 2. 初步认识UDP协议 3. 可靠传输与不可靠传输 四、网络字节序 1. 网络字节序的概念 2. 如何形成网络…

通过 ChatGPT 制作一个短视频

图文&#xff0c;生成视频 当通过 ChatGPT 生成连贯的 prompt 时&#xff0c;除了连环画&#xff0c;我们理所当然还可能畅想更激进的场景——生成动画视频。目前 AIGC 社区确实在生成视频方面有一定的尝试。比如 Deforum 可以通过多条 prompt&#xff0c;配合具体的切换时间点…