求更多在栈上分配任意空间的非标准跨编译器实现方案
在C++ constexpr函数中模拟GCC变长数组(VLA)行为的跨编译器方案
目前GCC支持在C++ constexpr函数中使用C变长数组(VLA),这是一个非标准扩展,但能实现预期的可变大小数组需求。为了兼容其他编译器(如Clang、MSVC),我已经实现了基于std::unique_ptr的标准降级方案,同时还总结了其他可行的跨编译器替代方案。
已实现的std::unique_ptr降级方案
该方案通过条件编译区分GCC和其他编译器,在非GCC环境下用堆分配的智能指针模拟VLA的使用方式:
class Integer { private: int i; public: constexpr Integer(const int& _t = 10) : i(_t) { } constexpr int get(void) const { return i; } }; #if defined(__GNUC__) && !defined(__clang__) #define XALLOC(type, name, count) type name[count] #else #include <memory> #define XALLOC(type, name, count) std::unique_ptr<type[]> __##name(new type[count]); type* name = &__##name[0] #endif constexpr int t(int num) { XALLOC(Integer, i, num); return i[0].get(); } constinit int nu = t(10); int main(int argc, const char *argv[]) { return t(0); }
其他跨编译器兼容方案
方案1:C++20 constexpr std::vector(推荐)
C20开始std::vector支持constexpr构造与操作,对于支持C20的编译器(Clang 15+、MSVC 2022+),可以直接用std::vector替代VLA,既符合标准又能在constexpr中使用:
#include <vector> #if defined(__GNUC__) && !defined(__clang__) #define XALLOC(type, name, count) type name[count] #elif __cplusplus >= 202002L #define XALLOC(type, name, count) constexpr std::vector<type> name(count) #else #include <memory> #define XALLOC(type, name, count) std::unique_ptr<type[]> __##name(new type[count]); type* name = &__##name[0] #endif constexpr int t(int num) { XALLOC(Integer, i, num); return i[0].get(); }
方案2:编译期静态数组+运行期动态分配的混合方案
如果数组大小在编译期可确定,优先使用std::array或静态数组;仅在运行期大小不确定时使用动态分配,结合if constexpr实现分支:
#include <array> #include <memory> template<int Num> constexpr int t_constexpr() { std::array<Integer, Num> i; return i[0].get(); } int t_runtime(int num) { std::unique_ptr<Integer[]> i(new Integer[num]); return i[0].get(); } constexpr int t(int num) { if constexpr (std::is_constant_evaluated()) { // 编译期调用时要求num是常量表达式 return t_constexpr<num>(); } else { return t_runtime(num); } } constinit int nu = t(10); // 编译期执行 int main(int argc, const char *argv[]) { return t(argc); // 运行期执行 }
方案3:运行期使用alloca(仅非constexpr场景)
alloca可以在栈上分配可变大小内存,性能优于堆分配,但不能在constexpr中使用,且存在栈溢出风险,仅适合运行期非constexpr的场景:
#include <cstdlib> #include <memory> #if defined(__GNUC__) && !defined(__clang__) #define XALLOC(type, name, count) type name[count] #else #define XALLOC(type, name, count) type* name = static_cast<type*>(alloca(sizeof(type) * count)); \ std::uninitialized_default_construct_n(name, count) #endif // 注意:此版本的t函数不能是constexpr int t(int num) { XALLOC(Integer, i, num); return i[0].get(); }
内容的提问来源于stack exchange,提问作者user23112128
相关产品推荐
相关产品推荐

