能否在constexpr函数中创建指向对象的std::array指针数组并返回?
问题核心原因
你遇到的编译错误本质是两个生命周期问题:
- 函数内局部
constexpr变量的生命周期和函数调用绑定,其地址不属于常量表达式,返回后会悬空 - 临时对象的地址在表达式结束后就失效,属于直接非法操作
可行实现方案
方案1:使用静态存储期constexpr实例(C++20及以上支持)
C++20允许在constexpr函数中定义static constexpr变量,这类变量属于全局静态存储期,地址可作为合法常量表达式使用。配合索引展开可以实现循环逻辑下的不同实例创建:
#include <array> #include <utility> struct AbstractPolynomial {}; template<typename T, std::size_t Degree> struct Polynomial : AbstractPolynomial { // 示例构造函数,按你的实际需求调整 constexpr Polynomial(std::initializer_list<T> coeffs) {} }; // 推导指引示例 template<typename T, typename... Ts> Polynomial(T, Ts...) -> Polynomial<T, sizeof...(Ts)>; template<std::size_t N> constexpr auto createArray() { std::array<const AbstractPolynomial*, N> res{}; // 索引序列展开替代普通循环,为每个位置的实例分配独立静态存储 [&]<std::size_t... Is>(std::index_sequence<Is...>) { auto fill_single = []<std::size_t I>() -> const AbstractPolynomial* { if constexpr (I % 2 == 0) { // 不同模板参数I对应唯一静态实例,不会重复定义 static constexpr auto even_poly = Polynomial{5}; return &even_poly; } else { static constexpr auto odd_poly = Polynomial{2, 5}; return &odd_poly; } }; ((res[Is] = fill_single.template operator()<Is>()), ...); }(std::make_index_sequence<N>{}); return res; } // 编译期测试 constexpr auto test_arr = createArray<10>(); static_assert(test_arr.size() == 10);
方案2:std::variant实现编译期多态(无指针,更安全)
如果你不需要运行期动态多态,只是要存储不同特化的Polynomial实例,用std::variant的纯值语义完全规避指针生命周期问题,不需要抽象基类,C++17即可使用:
#include <array> #include <variant> template<typename T, std::size_t Degree> struct Polynomial { constexpr Polynomial(std::initializer_list<T> coeffs) {} }; template<typename T, typename... Ts> Polynomial(T, Ts...) -> Polynomial<T, sizeof...(Ts)>; // 定义variant包含所有需要用到的Polynomial特化 using PolyVariant = std::variant<Polynomial<int, 0>, Polynomial<int, 1>>; template<std::size_t N> constexpr auto createArray() { std::array<PolyVariant, N> res{}; for (std::size_t i = 0; i < N; i++) { if (i % 2 == 0) { res[i] = Polynomial{5}; } else { res[i] = Polynomial{2, 5}; } } return res; } // 编译期测试 constexpr auto test_arr = createArray<10>();
后续访问实例时用std::visit即可匹配不同特化的Polynomial。
方案3:全局预定义实例(兼容性最好,C++17可用)
如果你的编译器不支持C++20,可以提前把所有需要用到的Polynomial实例定义为全局constexpr变量,直接取地址即可:
#include <array> struct AbstractPolynomial {}; template<typename T, std::size_t Degree> struct Polynomial : AbstractPolynomial { constexpr Polynomial(std::initializer_list<T> coeffs) {} }; template<typename T, typename... Ts> Polynomial(T, Ts...) -> Polynomial<T, sizeof...(Ts)>; // 全局预定义所有需要的实例 constexpr auto even_poly = Polynomial{5}; constexpr auto odd_poly = Polynomial{2, 5}; template<std::size_t N> constexpr auto createArray() { std::array<const AbstractPolynomial*, N> res{}; for (std::size_t i = 0; i < N; i++) { res[i] = (i % 2 == 0) ? &even_poly : &odd_poly; } return res; }
缺点是需要提前枚举所有要用到的Polynomial特化实例。
内容的提问来源于stack exchange,提问作者apopa
相关产品推荐
相关产品推荐

