8.2.2 C++11的通用属性
C++11语言中的通用属性使用了左右双中括号的形式:
[[attribute-list]]
这样设计的好处是:既不会消除语言添加或者重载关键字的能力,又不会占用用户空间的关键字的名字空间。
语法上,C++11的通用属性可以作用于类型、变量、名称、代码块等。对于作用于声明的通用属性,既可以写在声明的起始处,也可以写在声明的标识符之后。而对于作用于整个语句的通用属性,则应该写在语句起始处。而出现在以上两种规则描述的位置之外的通用属性,作用于哪个实体跟编译器具体的实现有关。
我们可以看几个例子。第一个是关于通用属性应用于函数的,具体如下:
[[attr1]]void func[attr2];
这里,[[attr1]]出现在函数定义之前,而[[attr2]]则位于函数名称之后,根据定义,[[attr1]]和[[attr2]]均可以作用于函数[func]。下一个是数组的例子:
[[attr1]]int array[[attr2]][10];
这跟第一个例子很类似,根据定义,[[attr1]]和[[attr2]]均可以作用于数组array。下面这个例子则稍显复杂:
[[attr1]]class C[[attr2]]{}[[attr3]]c1[[attr4]],c2[[attr5]];
这个例子声明了类C及其类型的变量c1和c2。本语句中,一共有5个不同的属性。按照C++11的定义,[[attr1]]和[[attr4]]会作用于c1,[[attr1]]和[[attr5]]会作用于c2,[[attr2]]出现在声明之后,仅作用于类C,而[[attr3]]所作用的对象则跟具体实现有关。
下面是一个switch-case加标签的例子:
[[attr1]]L1:
switch(value){
[[attr2]]case 1://do something…
[[attr3]]case 2://do something…
[[attr4]]break;
[[attr5]]default://do something…
}
[[attr6]]goto L1;
这里,[[attr1]]作用于标签L1,[[attr2]]和[[attr3]]作用于case 1和case 2表达式,[[attr4]]作用于break,[[attr5]]作用于default表达式,[[attr6]]作用于goto语句。下面的for语句也是类似的:
[[attr1]]for(int i=0;i<top;i++){
//do something…
}
[[attr2]]return top;
这里,[[attr1]]作用于for表达式,[[attr2]]作用于return。下面是函数有参数的情况:
[[attr1]]int func([[attr2]]int i,[[attr3]]int j)
{
//do something
[[attr4]]return i+j;
}
[[attr1]]作用于函数func,[[attr2]]和[[attr3]]分别作用于整型参数i和j,[[attr4]]作用于return语句。
事实上,在现有C++11标准中,只预定义了两个通用属性,分别是[[noreturn]]和[[carries_dependency]]。而在C++11标准委员会的最初提案中,还包含了形如[[final]]、[[override]]、[[restrict]]、[[hides]]、[[base_check]]等通用属性。不过最终,标准委员会只通过了以上两个,原因大概有以下几点:
❑final、override、restrict等是C++语言中需要支持的语言特性。通用属性从设计上讲,是可忽略的属性,其设计的目的主要是为了帮助编译器更好地检查代码中的错误或帮助编译器更好地优化代码。因此,语义相关的部分还是需要使用在关键字上。
❑预定义的通用属性应该是可移植的。一旦预定义了过多的通用属性,会导致C++代码的可移植性变弱。
❑C语言是没有通用属性的。
虽然看起来通用属性的使用受到了一些限制,但至少其语法规则为编译器厂商或组织提供了实现不同属性的办法。