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::属性1(参数列表),...命名空间n::属性n(参数列表)]] alignas(N)           (C++11 起)
  2. [[ using 命名空间X : 属性1(参数列表),...属性n(参数列表)]]                         (C++17 起)
  3. [[ 契约属性记号 契约等级(可选) 标识符(可选) : 表达式 ]]                              (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. 在声明语句最前面或者在函数名后面第1个位置.
    2. 契约属性和上面的不一样,它在参数之后,见 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 语法

  1. [[ expects 契约等级(可选) : 表达式 ]]              (C++20 起)
  2. [[ ensures 契约等级(可选) 标识符(可选) : 表达式 ]]    (C++20 起)
  3. [[ 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 起)的更多相关文章

  1. c++新特性实验(3)声明与定义:constexpr

    1.作用 constexpr 声明一个函数或变量,它的值可以在编译时出现在常量表达式之中. 2.constexpr 变量要求 其类型必须是 字面类型 (LiteralType) . 它必须被立即初始化 ...

  2. c++新特性实验(4)声明与定义:右值引用(C++11)

    1.作用 c++11以前,临时对象.字面常量一般情况下不可以再次访问,也不可以修改.右值引用可以解决这个问题. 1.1 实验A #include <iostream> using name ...

  3. MySQL8.0新特性实验1

    Server层,选项持久化 mysql> show variables like '%max_connections%';+------------------------+-------+| ...

  4. c++新特性实验(1)预处理

    1.参考资料 1.1 C++ C++17 标准文档(正式)  :    https://www.iso.org/standard/68564.html C++ 标准文档(草案)      :   ht ...

  5. 手把手教你如何用java8新特性将List中按指定属性排序,过滤重复数据

    在java中常常会遇到这样一个问题,在实际应用中,总会碰到对List排序并过滤重复的问题,如果List中放的只是简单的String类型过滤so easy,但是实际应用中并不会这么easy,往往List ...

  6. c++新特性实验(2)类型特性

    1. 基本类型 1.1 增加 long long long long int signed long long signed long long int unsigned long long unsi ...

  7. C++ 11 新特性:函数声明auto

    1.概览 1.1 函数名中的箭头,用来表明函数的return type,其使用在函数的返回类型需要通过模板参数进行推导,使用在decltype()和declval()不方便的场景 2.正文 c++ 中 ...

  8. C++11新特性实验

    #include <iostream> #include <vector> #include <map> #include <string> #incl ...

  9. ActiveReports 报表控件V12新特性 -- 新增矩表的RepeatToFill属性

    ActiveReports是一款专注于 .NET 平台的报表控件,全面满足 HTML5 / WinForms / ASP.NET / ASP.NET MVC / WPF 等平台下报表设计和开发工作需求 ...

随机推荐

  1. .Global.asax.cs中的方法的含义

    Application_Init:在每一个HttpApplication实例初始化的时候执行 Application_Disposed:在每一个HttpApplication实例被销毁之前执行 App ...

  2. 杜教筛&套路总结

    杜教筛 \[ \begin{split} (g*f)(i)&=\sum_{d|i}g(d)f(\frac id)\\ \Rightarrow g(1)S(n)&=\sum_{i=1}^ ...

  3. Matrix Power Series

    Matrix Power Series 给出矩阵A,求矩阵\(A+A^2+...+A^k\)各个元素\(mod\ yyb\)的值,\(n\leq 30,k\leq 10^9,yyb\leq 10^4\ ...

  4. soj97 旅行

    题意:给你一棵n个点的树.m个操作,op 1:在点i上建立银行.op 2:询问从点x开始可以经过至少一个银行走到的点中编号第二大的点. n,m<=1e5. 标程: #include<bit ...

  5. 阿里云容器服务通过LoadBalancer暴露IPv6服务

    背景: IPv4地址已接近枯竭,被誉为下一代互联网技术的IPv6成为新的“全球互联网门牌号”,它可以让地球上的每一粒沙子都拥有地址.当下,各国都在加速推进下一代互联网的部署,工信部也互联网服务商提出了 ...

  6. LUOGU P1613 跑路 (倍增floyd)

    解题思路 倍增$floyd$,首先设$f[i][j][k]$表示$i$这个点到$j$的距离能否为$2^k$,初值是如果x,y之间有边,那么$f[x][y][0]=1$.转移方程就是$f[i][j][t ...

  7. H5在部分苹果手机IOS系统下重力感应无效

    原因不明,反正在IOS系统12.2以上的普通的H5移动端网页的重力感应功能无反应 解决方法: 把链接改为HTTPS,经过测试,12.2系统以上的如果你的链接是HTTP的,重力感应在网页上是没调起的,改 ...

  8. 运行pip报错:Fatal error in launcher: Unable to create process using '’路径’'

    参考此文:https://blog.csdn.net/cjeric/article/details/73518782 win7笔记本安装了Python2.7,Python3.7,以及anaconda3 ...

  9. Android之AbsoluteLayout(绝对布局)

    1.属性简介 为了适配不同机型,绝对布局使用很少! android:layout_x="50dp" android:layout_y="100dp"也只有在Ab ...

  10. iBatis 代码自动生成工具 iBator 及 Example 使用

    iBator的下载和安装 官方下载地址:http://people.apache.org/builds/ibatis/ibator/ 安装:见<Eclipse 插件安装> 安装完成后,“F ...