C++通过带参构造函数实现编译时静态分配遇constexpr编译错误求助
编译时静态分配带参构造类对象的问题与解决
需求与尝试代码
想要通过带参构造函数创建编译时静态分配的类对象,传入编译时常量参数,先给出动态分配的示例:
#include <iostream> #include <vector> #include <cstdint> class myclass { private: std::vector<uint32_t> myvec; public: myclass(uint32_t num_elem) { myvec.resize(num_elem); } void print_vec() { for(int i: this->myvec) std::cout << i << std::endl; } }; int main() { myclass* obj = new myclass(10); (*obj).print_vec(); delete obj; return 0; }
尝试改为静态分配的代码:
#include <iostream> #include <vector> #include <cstdint> class myclass { private: std::vector<uint32_t> myvec; public: myclass(uint32_t num_elem) { myvec.resize(num_elem); } constexpr void print_vec() { for(int i: this->myvec) std::cout << i << std::endl; } }; int main() { constexpr myclass obj(10); obj.print_vec(); return 0; }
编译(g++ --std=c++20 test2.cpp)时出现错误:
test2.cpp: In function ‘int main()’: test2.cpp:24:27: error: the type ‘const myclass’ of ‘constexpr’ variable ‘obj’ is not literal 24 | constexpr myclass obj(10); | ^~~ test2.cpp:5:7: note: ‘myclass’ is not literal because: 5 | class myclass | ^~~~~~~ test2.cpp:5:7: note: ‘myclass’ is not an aggregate, does not have a trivial default constructor, and has no ‘constexpr’ constructor that is not a copy or move constructor test2.cpp:25:22: error: passing ‘const myclass’ as ‘this’ argument discards qualifiers [-fpermissive] 25 | obj.print_vec(); | ~~~~~~~~~~~~~^~ test2.cpp:15:32: note: in call to ‘constexpr void myclass::print_vec()’ 15 | constexpr void print_vec() | ^~~~~~~~~
错误原因分析
1. constexpr对象的类型必须是字面类型
constexpr变量要求其类型是字面类型(literal type),而你的myclass包含std::vector<uint32_t>:
std::vector依赖运行时动态堆分配内存,不属于字面类型,因此包含它的myclass也无法成为字面类型,直接导致constexpr myclass obj(10)报错。- 另外,你的构造函数没有声明为
constexpr,即使补上constexpr,因为vector的存在,依然无法满足字面类型要求。
2. const对象无法调用非const成员函数
constexpr变量默认是const属性的,而print_vec没有声明为const成员函数,因此调用时会触发权限错误,需要将其改为constexpr void print_vec() const。
解决方案:使用编译时固定大小的容器
要实现编译时静态分配,必须替换std::vector为编译时大小确定的容器,比如std::array(属于字面类型)。推荐用模板参数指定容器大小,这样可以灵活控制元素数量:
#include <iostream> #include <array> #include <cstdint> template<uint32_t NumElem> class myclass { private: std::array<uint32_t, NumElem> myarr{}; // 编译时初始化全0 public: // 聚合类型默认构造即可,也可显式声明constexpr构造 constexpr myclass() = default; // 声明为const成员函数,允许const对象调用 constexpr void print_vec() const { for (uint32_t i : myarr) std::cout << i << std::endl; } }; int main() { constexpr myclass<10> obj; // 编译时静态分配内存 obj.print_vec(); return 0; }
说明:
std::array的大小是编译时常量,属于字面类型,因此myclass可以满足constexpr变量的类型要求,实现编译时静态分配。- 模板参数
NumElem指定元素数量,保证编译时确定大小,符合你的需求。 print_vec声明为const成员函数,允许constexpr(即const)对象调用。
注意:std::cout属于运行时IO操作,即使print_vec是constexpr函数,也无法在编译时直接将输出嵌入二进制,只能在程序运行时执行输出逻辑。
内容的提问来源于stack exchange,提问作者Setu
相关产品推荐
相关产品推荐

