编译时生成指定最大值以内素数的std::array,如何消除代码重复?
避免生成素数std::array时重复调用make_primes的方法
你需要生成包含不超过30的素数的std::array,当前代码中重复调用make_primes(MAX_PRIME)来获取素数列表和数组大小,导致冗余。以下是两种解决方法:
原始代码问题点
在初始化primes数组的lambda中,先后两次调用make_primes(MAX_PRIME):一次获取素数vector,另一次获取vector的size作为std::array的模板参数,造成不必要的重复计算。
#include <iostream> #include <cstdint> #include <vector> #include <array> using namespace std; constexpr vector<int> make_primes(int max_prime) noexcept { vector<int> primes; primes.push_back(2); for (int p = 3; p < max_prime; ) { primes.push_back(p); int i; do { p += 2; i = 1; for (; i < primes.size(); ++i) { if ((p % primes[i]) == 0) break; } } while (i != primes.size()); } return primes; } constexpr int MAX_PRIME = 30; // 2 3 5 7 11 13 17 19 23 29 constexpr auto primes { []() { auto primes = make_primes(MAX_PRIME); constexpr auto N = make_primes(MAX_PRIME).size(); // 重复调用 std::array<int, N> arr; for (int i = 0; i < arr.size(); ++i) arr[i] = primes[i]; return arr; }() }; int main() { cout << primes.size() << ':'; for (int x : primes) cout << ' ' << x; cout << endl; return 0; }
方案1:提前定义constexpr素数vector(C++17及以上)
将make_primes的结果提前存储为一个constexpr vector,后续直接复用它的元素和大小,只调用一次生成函数:
#include <iostream> #include <cstdint> #include <vector> #include <array> using namespace std; constexpr vector<int> make_primes(int max_prime) noexcept { vector<int> primes; if (max_prime < 2) return primes; primes.push_back(2); for (int p = 3; p <= max_prime; ) { primes.push_back(p); int i; do { p += 2; i = 1; for (; i < primes.size(); ++i) { if ((p % primes[i]) == 0) break; } } while (i != primes.size() && p <= max_prime); } return primes; } constexpr int MAX_PRIME = 30; constexpr auto primes_vec = make_primes(MAX_PRIME); // 仅调用一次 constexpr std::array<int, primes_vec.size()> primes = []{ std::array<int, primes_vec.size()> arr{}; for (size_t i = 0; i < arr.size(); ++i) arr[i] = primes_vec[i]; return arr; }(); int main() { cout << primes.size() << ':'; for (int x : primes) cout << ' ' << x; cout << endl; return 0; }
方案2:在constexpr lambda内复用vector(C++20及以上)
C++20放宽了constexpr上下文的限制,允许在lambda内用constexpr变量作为非类型模板参数,直接在lambda内部生成一次vector并复用:
#include <iostream> #include <cstdint> #include <vector> #include <array> using namespace std; constexpr vector<int> make_primes(int max_prime) noexcept { vector<int> primes; if (max_prime < 2) return primes; primes.push_back(2); for (int p = 3; p <= max_prime; ) { primes.push_back(p); int i; do { p += 2; i = 1; for (; i < primes.size(); ++i) { if ((p % primes[i]) == 0) break; } } while (i != primes.size() && p <= max_prime); } return primes; } constexpr int MAX_PRIME = 30; constexpr auto primes = []() { constexpr auto primes_vec = make_primes(MAX_PRIME); // 仅调用一次 std::array<int, primes_vec.size()> arr{}; for (size_t i = 0; i < arr.size(); ++i) arr[i] = primes_vec[i]; return arr; }(); int main() { cout << primes.size() << ':'; for (int x : primes) cout << ' ' << x; cout << endl; return 0; }
两种方案都能避免重复调用make_primes,方案1兼容C17,方案2利用C20特性让代码更紧凑。
内容的提问来源于stack exchange,提问作者Mishka
相关产品推荐
相关产品推荐

