编译期编程

简介: 编译期编程

自从c++98开始,可以使用循环和路径选择执行的方式,在程序编译期执行计算。比如计算一个数是否为素数,可以使用如下的模板来实现:

template<unsigned p, unsigned d>
struct DoIsPrime
{
    static constexpr bool value = (p%d != 0) && DoIsPrime<p, d-1>::value;
};
template<unsigned p>
struct DoIsPrime<p,2>
{
    static constexpr bool value = (p%2 != 0);
};
template<unsigned p>
struct IsPrime
{
    static constexpr bool value = DoIsPrime<p,p/2>::value;
};
//call the template function
std::cout << IsPrime<9>::value << std::endl;

这里有两个问题:

  1. 为什么要声明为static?
  2. 是如何在编译期执行计算的?

先看问题1,声明为static是由于当实例化类时,类中的静态成员变量归类所有,所有对象共享统一份静态成员变量。换句话说,类特化时,不需要再定义对象即可使用该类中的静态数据。

再回答问题2,这里采用递归的方式展开计算。把展开过程梳理为:

IsPrime<9> ---> IsPrime<9,4>::value ---> 9%4 != 0 && DoIsPrime<9,3>::value ---> true && 9%3 !=0 && DoIsPrime<9,2>::value

在最后一步,由于9%3 != 0 是 false,根据经验,由前两项已经知道结果为false了,最后一个项根本不会计算,所以好像DoIsPrime<9,2>根本不会实例化。但是,这些是在编译期完成的!,因此还是会实例化。

当然还有比较清晰明了的普通函数式的写法

constexpr bool isPrime (unsigned int p)
{
    for (unsigned int d = 2; d <= p/2; ++d){
        if (p % d == 0){
            return false;
        }
    }
    return p > 1;
}
//call the template function
std::cout << isPrime(9) << std::endl;

从c++14开始,常量表达式在编译期完成计算,且支持循环等结构,不需要把所有语句在一行内完成。因此上面的函数也是在编译期完成的。

相关文章
|
6月前
|
IDE 编译器 开发工具
编程前的准备:编译器的安装
编程前的准备:编译器的安装
30 0
|
程序员 编译器 Linux
G0 语言编译运行说明 | 学习笔记
快速学习 G0 语言编译运行说明
87 0
|
存储 安全 编译器
基础C程序的开发和编译
基础C程序的开发和编译
基础C程序的开发和编译
|
Java 编译器 前端开发
烂尾工程: Java实现的汇编语言编译器
一个半拉子工程, 用Java实现的汇编语言编译器的介绍. 代码中使用中文命名. An unfinished project, an assembler implemented in Java, with naming in Chinese.
1132 0