Skip to content

Latest commit

 

History

History
83 lines (57 loc) · 3.29 KB

a10.md

File metadata and controls

83 lines (57 loc) · 3.29 KB

属性和断言

C++程序生命周期里存在"编码阶段"和"预处理阶段",它的主要工作是生成人类可识别的源码。而"编译阶段"的目标是生成计算机可识别的机器码

属性(attribute)

"预处理编程"是指通过预处理指令如#define#include来控制预处理器的。

与此同时存在控制编译器的"编译指令"。

gcc中的__attribute__就是编译指令,告知编译器要对齐其修饰的结构体内存。

C++ 11中的属性即是和__attribute__一样的编译指令,命名为属性

给变量,函数,类等"贴"上一个编译阶段的标签方便编译器识别处理。

属性的语法是[[...]],中间的即是属性标签。

[[noreturn]]        // 属性标签
int func(bool flag) // 函数绝不会返回值
{
    throw std::runtime_error("xx");
}

C++ 11里仅有两个属性noreturncarries_dependency

C++ 14里增加了deprecated用来标记不推荐使用的变量,函数和类(废弃的)

比如你原来写了一个func1后来觉得不够好重写了完全不同的新函数func2,老函数已经被不少人使用了,立即删除不太可能,此时就加个一deprecated标签,这样在编译时如果用到了这个函数就会输出告警。

deprecated:与 C++14 相同,但可以用在 C++11 里。 unused:用于变量、类型、函数等,表示虽然暂时不用,但最好保留着,因为将来可能 会用。 constructor:函数会在 main() 函数之前执行,效果有点像是全局对象的构造函数。 destructor:函数会在 main() 函数结束之后执行,有点像是全局对象的析构函数。 always_inline:要求编译器强制内联函数,作用比 inline 关键字更强。 hot:标记“热点”函数,要求编译器更积极地优化 nodiscard: c++17里面个人认为很重要的一个属性,一般用于修饰函数,告诉函数调用者必须关注该函数的返回值(即不能丢弃该函数的返回值)。如果函数调用者未将该函数的返回值赋值给一个变量,则编译器会给出一个警告。

静态断言(static_assert)

先看assert(动态断言)用来断言一个表达式必定为真。

assert(i > 0 && "i must be greater than zero");

程序运行到assert语句时会计算表达式的值,为false则会输出错误消息,然后调用abort终止程序的执行。

静态断言则相反,不会在运行时生效只会在编译时生效。

它是在编译阶段里检测各种条件的“断言”,编译器看到static_assert也会计算表达式的值,如果值是false就会报错导致编译失败。

比如计算斐波那契数列的模板元编程风格代码如下:

#include <cstdio>

template <int n>
struct factorial {
    static_assert(
        n >= 0,
        "Arg must be non-negative");
    static const int value =
        n * factorial<n - 1>::value;
};
template <>
struct factorial<0> {
    static const int value = 1;
};

int main()
{
    printf("%d\n", factorial<10>::value);
}

注意普通的factorial模板函数,可以通过静态断言保证模板参数必须大于等于零。

同时要注意静态断言运行在编译阶段,只能看到编译时的常数和类型。看不到运行时的变量、指针、内存数据等。