C++如何通过constexpr实现编译期初始化前10000个素数数组
问题根因说明
constexpr函数要求调用时必须能看到完整定义,你之前将is_prime和init_prime的实现放在单独的cpp文件,头文件仅提供声明,编译main.cpp时看不到函数实现,无法完成编译期计算,就会出现链接错误。- 默认无优化编译时,就算所有代码放在同一个文件,编译器也不会主动执行
constexpr函数的编译期求值,必须显式要求常量初始化,同时开启至少O1优化。 - 你原来的素数判断算法效率极低,哪怕是编译期计算,也要花费很长时间,建议优化判断上限到
sqrt(i)。
可行实现方案
方案1:使用constexpr数组完成编译期初始化(C++17及以上版本支持)
直接把所有constexpr逻辑放在头文件中,显式要求常量初始化:
首先prime.h代码:
#include <array> constexpr int prime_size = 10000; constexpr bool is_prime(int i) { if (i <= 1) return false; if (i == 2) return true; if (i % 2 == 0) return false; // 优化判断上限到sqrt(i),大幅降低计算量 for (int j = 3; j * j <= i; j += 2) { if (i % j == 0) { return false; } } return true; } constexpr std::array<int, prime_size> init_prime() { std::array<int, prime_size> prime{}; int prime_counter = 1; prime[0] = 2; int current = 3; while (prime_counter < prime_size) { if (is_prime(current)) { prime[prime_counter++] = current; } current += 2; } return prime; } // 显式constexpr声明,强制编译期初始化 constexpr std::array<int, prime_size> prime = init_prime();
主程序代码:
#include <iostream> #include "prime.h" int main() { // 不需要再调用初始化函数,数组已经在编译期完成填充 std::cout << prime[8] << std::endl; return 0; }
编译时添加参数-std=c++17 -O1即可,mingw64完全支持该语法。编译阶段会花费少量时间计算素数,编译完成后运行程序无任何初始化耗时,数组直接存储在程序的只读数据段。
方案2:代码生成方案(全版本兼容)
写一个简单的小程序提前生成所有10000个素数,直接输出成int prime[10000] = {2,3,5,...};的初始化代码,将该初始化语句直接放入头文件即可,不需要任何运行时或编译期计算,兼容性最好。
注意事项
- 不要把
constexpr函数的实现放在单独的cpp文件中,必须和调用点放在同一个翻译单元,或者放在头文件中让调用点可以引入完整实现 - 必须开启至少O1优化,否则gcc默认不会执行编译期的
constexpr求值 - 优化素数判断算法可以大幅降低编译期计算的耗时,优化到sqrt(n)判断上限后,计算10000个素数仅需要几毫秒
内容的提问来源于stack exchange,提问作者user1724871284
相关产品推荐
相关产品推荐

