编译是预处理之后的阶段,它的输入是(经过预处理的)C++ 源码,输出是二进制可执行文件(也可能是汇编文件、动态库或者静态库)。这个处理动作就是由编译器来执行的。
编译阶段的特殊性在于,它看到的都是 C++ 语法实体,比如 typedef、using、template、struct/class 这些关键字定义的类型,而不是运行阶段的变量。
下面举例说明
template<int N>
struct fib // 递归计算斐波那契数列
{
static const int value = fib<N - 1>::value + fib<N - 2>::value;
};
template<>
struct fib<0> // 模板特化计算fib<0>
{
static const int value = 1;
};
template<>
struct fib<1> // 模板特化计算fib<1>
{
static const int value = 1;
};
// 调用后输出2,3,5,8
cout << fib<2>::value << endl;
cout << fib<3>::value << endl;
cout << fib<4>::value << endl;
cout << fib<5>::value << endl;
可以把它理解为给变量、函数、类等“贴”上一个编译阶段的“标签”,方便编译器识别处理。C++11 之后有标准支持。
[[noreturn]] // 属性标签
int func(bool falg) { // 函数绝不会返回任何值
throw std::runtime_error("xxx");
}
不过,在 C++11 里只定义了两个属性:“noreturn”和“carries_dependency”,它们基本上没什么大用处。
C++14 的情况略微好了点,增加了一个比较实用的属性“deprecated”,用来标记不推荐使用的变量、函数或者类,也就是被“废弃”。
[[deprecated("deadline:2020-12-31")]] // C++14 or later
int old_func();
GCC 还额外扩展了一些属性,如下