c++新特性实验(5)声明与定义:属性列表(C++11 起)
1.初识属性
1.1 实验A: noreturn 属性
[[ noreturn ]] static void
thread1(void *data){
cout << "noreturn " << endl;
while(){
this_thread::sleep_for(2s);
cout << "sleeping " << endl;
}
}
结果:
noreturn
sleeping
sleeping
sleeping
...
其中的[[ noreturn ]] 就是属性列表,其中 [[ ... ]] 内可以有多个属性,noreturn这个属性告诉编译器,这个函数不返回,如果在代码中返回了(正常执行完毕或者用return),那么编译产生警告。
1.2 标准属性
C++ 标准仅定义下列属性。
属性 |
版本 |
修饰目标 | 作用 |
[[noreturn]] |
C++11 |
函数 |
指示函数不返回,没有return语句,不正常执行完毕,但是可以通过出异 常或者exit()函数退出。 |
[[carries_dependency]] |
C++11 |
函数、变量 | 指示释放消费 std::memory_order 中的依赖链传入和传出该函数。 |
[[deprecated("reason")]] |
C++14 |
函数、变量、类等 |
声明有此属性的名称或实体被弃用,"reason"是原因,支持中文,原因可为空。 |
[[fallthrough]] |
C++17 |
case语句 | 声明前一 个case 标号没有break是有意的,此时编译器不需要发出警告。 |
[[nodiscard]] |
C++17 |
函数 | 若返回值被舍弃,则鼓励编译器发布警告。 |
[[maybe_unused]] |
C++17 |
函数、变量、类等 | 使用该属性的标识符,即使未使用,编译器也不发出警告。 |
[[likely]][[unlikely]] |
C++20 |
标号、语句(非声明语句) |
likely指示编译器应该对该语句的执行路径比其他执行路径进行更多的优化。 unlikely与之相反。 |
[[no_unique_address]] |
C++20 |
非位域、非静态数据成员 | 非静态数据成员不需要拥有不同于其类的所有其他非静态数据成员的地址。 |
[[expects]][[ensures]][[assert]] |
C++20 |
函数 | 为函数指定契约属性 |
[[optimize_for_synchronized]] |
TM TS |
函数 | 应该针对来自 synchronized 语句的调用来优化该函数定义 |
编译器厂商也可以自定义属性。例如 GNU 的 [[hot]]、[[always_inline]],微软的 [[__declspec(xxx)]] 等。
2.语法
2.1 属性列表语法
[[命名空间1::属性1(参数列表),...命名空间n::属性n(参数列表)]] alignas(N)(C++11 起)[[using命名空间X:属性1(参数列表),...属性n(参数列表)]](C++17 起)[[契约属性记号 契约等级(可选) 标识符(可选):表达式]](C++20 起)
其中
- 属性可用在 C++ 程序中的几乎所有声明语句中:类型、变量、函数、代码块、整个翻译单元,命名空间除外。
- 每个特定的属性都仅在使用处有效.所有未定义的属性均被忽略,且不产生错误。 (C++17 起)
- 属性可出现在整个声明语句之前、或直接跟在被声明实体的名字之后,大多数其他情形中,属性应用于直接位于其之前的实体。
- 第1条语法中,如果属性在当前命名空间或者使用了using namespace xxx,xxx是属性所在命名空间,命名空间可以省略,属性没有参数时参数也略。
- 第1条语法中,alignas(N),N为0或者非2的幂时无效。也可以省略掉alignas使用默认对齐。
- 表1.2中c++定义的标准属性并不是std命名空间下的。无需加std:: .
- 第2条语法中,属性1...n都是命名空间X内的,且属性前不用(也不可以)像语法1一样指定命名空间。
- 第3条见 3.契约属性
2.2 实验B:使用未定义的属性
[[ hhahahahahahaha ]] int //error,使用未定义的属性
fun1(void*){
cout << " not return int" << endl;
}
结果,属性被忽略并产生一个警告。
attr.cpp:20:11: warning: ‘hhahahahahahaha’ attribute directive ignored [-Wattributes]
fun1(void*){
2.3 实验C:属性的位置
- 属性与变量:在声明语句最前面或者在变量名后面第1个位置.
正确语法:
[[deprecated]] int n1 = ; //ok
int n2 [[deprecated]] = ; //ok int && ref2 [[deprecated]] = ; //ok
int nn = ;
[[deprecated]]int *p1 = & nn; //ok
错误语法:
int [[deprecated]] n3 = ; //error,
// int n3 = 100 [[deprecated]]; //error,
int && [[deprecated]] ref1 = ; //error
错误结果:
attr.cpp:136:9: warning: attribute ignored [-Wattributes]
int [[deprecated]] n3 = 100; //error,
^
attr.cpp:136:9: note: an attribute that appertains to a type-specifier is ignored
attr.cpp:138:27: warning: attribute ignored [-Wattributes]
int && [[deprecated]] ref1 = 1; //error
^~~~
attr.cpp:138:27: note: an attribute that appertains to a type-specifier is ignored
当有const,static,extern,register,auto修饰时也是这个规则。第7行是错误的。
//有static,extern,register,auto、const等修饰时
[[deprecated]] const static int n5 = ; //ok,
[[deprecated]] extern int n6; //ok,
[[deprecated]] register char n7; //c++11 ok,c++17 error,c++17不支持register存储类别了。
[[deprecated]] auto n8 = ; //ok, static [[deprecated]] int n4 = ; //error,
当变量是成员变量、全局变量、形式参数时,也是这个规则。第13行错误。
//属性与外部变量
[[deprecated]] extern int g_count ; //ok
//属性与形参
void
foo([[deprecated]] int arg1,int arg2 [[deprecated]],int arg3 [[deprecated]] = 10){
} //属性与成员变量
class ATT{
public:
[[deprecated]] int a1 ;
int a2 [[deprecated]] ;
int [[deprecated]] a3 ; //error
};
- 属性与函数:
- 在声明语句最前面或者在函数名后面第1个位置.
- 契约属性和上面的不一样,它在参数之后,见 3.契约属性(c++20)
正确语法
#define REASON "使用cout"
[[deprecated(REASON)]] void fun1(){} //ok,属性声明在语句最前面 void fun2 [[deprecated(REASON)]](){} //ok,属性在声明实体后+1个位置 [[ noreturn ]] static void fun3(){throw ;} //ok inline void fun4 [[ noreturn ]](){throw ;} //ok [[nodiscard]] extern int fun5 [[deprecated]](){return ;}//ok
错误语法
int [[nodiscard]]fun6(){ } //error,属性在声明实体前1个位置
void fun7() [[nodiscard]]{ } //error,属性在声明实体后+2个位置起
成员函数友元函数同样是这个规则
class FATTR{
[[nodiscard]] int fun1(){} //ok
int [[nodiscard]] fun2() {} //error,属性在声明实体前1个位置
[[nodiscard]] friend int friend1() {} //ok
friend int friend2 [[nodiscard]]() {} //ok
//friend int [[nodiscard]]() friend3 {} //error.
};
多个属性
[[ noreturn,deprecated(U"utf32") ]] void //同时声明多个属性
fun8(){
cout << "同时声明多个属性" << endl;
throw ;
}
[[gnu::always_inline]] [[gnu::hot]] [[gnu::const]] [[nodiscard]]
inline int fun9(bool ){ //分开声明多个属性 }
- 属性与类、结构,联合、枚举:只能在关键字class、struct、union、enum和名字之间使用属性。
正确语法:
class [[deprecated]] A{}; //ok,标准写法,在class之后,类名之前。这个属性声明A过期了。在使用A的地方有警告提示。
错误语法:
[[deprecated]] class B{}; //error,在声明语句之前。
//class C [[deprecated]] {}; //error,属性在类的后面编译不过。
class D{}[[deprecated]] ; //error,
class E[[deprecated]] ; //ok,虽然不会警告,但是在定义E的时候,已经失去了deprecated的含义。
class E {};
struct、enum、unio同理
//union u1 [[deprecated]]{}; //error
//struct s1[[deprecated]]{}; //error
enum [[deprecated]] E1 {}; //ok
//[[deprecated]] enum E2 {}; //error,
- 属性与命名空间:命名空间不可以使用属性
//namespace [[deprecated]] N1{}; //error,命名空间不可以使用属性
//namespace N2 [[deprecated]]{}; //error,不可以在命名空间名字后面
//[[deprecated]] namespace N3 {}; //error,编译不过
2.4 实验D:属性声明using写法
正确语法:
[[using NS: opt(), debug]] int i1; // ok:同 [[NS::opt(1), NS::debug]]
- 使用using NS后,不必再使用NS::属性这种语法
[[using NS: NS::opt()]] int io; // error:使用using NS后,不必再使用NS::属性这种语法
- 在使用using的[[ ]] 内,不可以有其它命名空间
[[using NS: opt(), debug,gnu::hot]] int i2; // error:不可以有其它命名空间
- 其中的属性必需同时是命名空间NS下的属性或者标准属性,如
[[using NS: opt(), debug,deprecated]]int i3; // ok:但是可以有标准的属性
- 如果想同时声明多个属性又想使用using语法:那要分开声明属性
[[using NS: opt(), debug]] int i5 [[using gnu:const,hot,always_inline]];// ok:分开使用using
3.契约属性(c++20)
3.1 作用
为函数指定:
- 在被调用前参数应该满足的条件、
- 执行完毕后返回值应该満的条件和
- 函数执行过程中语句的断言。
如果条件不满足,则指定的违约处理函数被执行。
3.2 语法
[[expects契约等级(可选):表达式]](C++20 起)[[ensures契约等级(可选) 标识符(可选):表达式]](C++20 起)[[assert契约等级(可选):表达式]](C++20 起)
其中:
- 契约等级 ,值是 default、audit 、axiom 之一;默认为 default
- 表达式是按语境转换成 bool 的表达式,且其顶层运算符不能是赋值或逗号运算符。
- 表达式运行是不能有副作用。
- 若表达式有异常,则std::terminate()被调用。
- 如想使用契约属性,函数的首个声明必须指定它,后续的声明与定义要与它保持一致。
- 如果友元使用契约属性,则该声明必须是定义且该编译单元唯一的声明。
- 第2条中:标识符用来代表函数返回值的标识符
- 第2条中:当契约等级 与 标识符 产生歧义时,按契约等级解理。
3.3 违约处理
如果契约条件不满足,则违约处理函数被执行。它的声明如下:
void (const std::contract_violation &) noexcept;
其中
contract_violation是std下的一个类,描述关于契约违规的信息,如:行号、文件名、函数名、契约等级等等。- 这个违约函数通常由编译器实现。
用户可以指定违约处理函数执行完毕后程序继续的模式:
- 不断续执行,调用 std::terminate() 退出 。(默认)
- 断续执行。
3.4 实验E:契约属性
由于c++20还没有正式发布,现在(2019/07/23) gcc 9.1.1还不支持这个特性。
void
fcv_catch(const std::contract_violation & cv) noexcept{ } void fun100(int ); void fun100(int); void fun100(int){ } int fcv(int i) [[expects: i > ]] [[ensures audit x: x < ]] ; //ok int fcv(int n) [[expects: n > ]] [[ensures audit y: y < ]] ; //ok [[ensures audit y: y < ]] int fcv2(int n) [[expects: n > ]]; //error class FCV{ friend int f3(int n) [[expects: n > ]] ; //error,不是定义
friend int fop(int n) [[expects: n > ]] { //ok }
} int fcv(int i) [[expects: i > ]] [[ensures audit x: x < ]] {
i++;
float x = ;
return x;
}
4. 查寻属性是否存在
__has_cpp_attribute(xxx) 这个宏可以查寻属性是否存在。
void
fu(){ #if __has_cpp_attribute(opt)
cout << "has opt" << endl;
#else
cout << "not found opt" << endl;
#endif }
c++新特性实验(5)声明与定义:属性列表(C++11 起)的更多相关文章
- c++新特性实验(3)声明与定义:constexpr
1.作用 constexpr 声明一个函数或变量,它的值可以在编译时出现在常量表达式之中. 2.constexpr 变量要求 其类型必须是 字面类型 (LiteralType) . 它必须被立即初始化 ...
- c++新特性实验(4)声明与定义:右值引用(C++11)
1.作用 c++11以前,临时对象.字面常量一般情况下不可以再次访问,也不可以修改.右值引用可以解决这个问题. 1.1 实验A #include <iostream> using name ...
- MySQL8.0新特性实验1
Server层,选项持久化 mysql> show variables like '%max_connections%';+------------------------+-------+| ...
- c++新特性实验(1)预处理
1.参考资料 1.1 C++ C++17 标准文档(正式) : https://www.iso.org/standard/68564.html C++ 标准文档(草案) : ht ...
- 手把手教你如何用java8新特性将List中按指定属性排序,过滤重复数据
在java中常常会遇到这样一个问题,在实际应用中,总会碰到对List排序并过滤重复的问题,如果List中放的只是简单的String类型过滤so easy,但是实际应用中并不会这么easy,往往List ...
- c++新特性实验(2)类型特性
1. 基本类型 1.1 增加 long long long long int signed long long signed long long int unsigned long long unsi ...
- C++ 11 新特性:函数声明auto
1.概览 1.1 函数名中的箭头,用来表明函数的return type,其使用在函数的返回类型需要通过模板参数进行推导,使用在decltype()和declval()不方便的场景 2.正文 c++ 中 ...
- C++11新特性实验
#include <iostream> #include <vector> #include <map> #include <string> #incl ...
- ActiveReports 报表控件V12新特性 -- 新增矩表的RepeatToFill属性
ActiveReports是一款专注于 .NET 平台的报表控件,全面满足 HTML5 / WinForms / ASP.NET / ASP.NET MVC / WPF 等平台下报表设计和开发工作需求 ...
随机推荐
- 面试系列13 redis都有哪些数据类型
(1)string 这是最基本的类型了,没啥可说的,就是普通的set和get,做简单的kv缓存 (2)hash 这个是类似map的一种结构,这个一般就是可以将结构化的数据,比如一个对象(前提是这个对象 ...
- JS数组 了解成员数量(数组属性length) myarr.length
了解成员数量(数组属性length) 如果我们想知道数组的大小,只需引用数组的一个属性length.Length属性表示数组的长度,即数组中元素的个数. 语法: myarray.length; //获 ...
- 改变 HTML 样式 Object.style.property=new style;
改变 HTML 样式 HTML DOM 允许 JavaScript 改变 HTML 元素的样式.如何改变 HTML 元素的样式呢? 语法: Object.style.property=new styl ...
- android 中的一些小问题
1 TextView 在TableRow 中占满一行 要为TextView设置 android:layout_weight="1" 这个属性 2
- AndroidStudio 添加翻译插件
添加方式 第一步 在AndroidStudio的菜单栏里找到 File > Settings > 点击 . 第二步 点击Plugins > 在点击Marketplace 等待插件列表 ...
- C++Builder 常用String
关于AnsiSting的使用大全(1) arrow: Ansistring 转 char 代码: void __fastcall TForm1::Button1Click(TObject *Sende ...
- SPOJ 1043 GSS1 - Can you answer these queries I
题目描述 给出了序列A[1],A[2],-,A[N]. (a[i]≤15007,1≤N≤50000).查询定义如下: 查询(x,y)=max{a[i]+a[i+1]+-+a[j]:x≤i≤j≤y}. ...
- Android开发随笔
1.线性布局LinearLayout时,用到layout_weight权重的使用 控件的宽度(高度)=自身宽度(高度)+剩余空间的所占比例 剩余空间(可以为负值)=屏幕宽-所有控件宽度(高度)< ...
- WhaleCTF之隐写-Find
WhaleCTF之隐写-Find 前往题目 图片保存到本地,用Stegsolve打开图片 找到二维码 用微信或qq扫描,得到flag~
- 目标检测从入门到精通—SPP-Net详细解析(三)
SPP-Net网络结构分析 Author:Mr. Sun Date:2019.03.18 Loacation: DaLian university of technology 论文名称:<Spa ...