模板问题:如何将ifstream读取值作为非类型模板实参传入?
为啥会报错?
C++里模板的非类型参数(就是你SMatrix<T, N>里的N)有个硬性要求:必须是编译期就能确定的常量表达式。你从文件里读出来的M是运行时才知道的值,编译器在编译代码的时候根本不知道它会是多少,自然就会抛出那个错误——把运行时的普通int当模板非类型参数是不允许的。
怎么解决?
既然矩阵大小要到运行时才能确定,那咱们得换个思路,不能再靠模板参数来固定数组大小了。这里有两种常用方案:
方案1:用动态容器替代固定数组(最通用推荐)
重构你的SMatrix类,用std::vector来存储元素,这样大小可以在构造对象的时候动态传入:
#ifndef T_SIMPLE_MATRIX_H #define T_SIMPLE_MATRIX_H #include <vector> template<class T> class SMatrix { private: std::vector<T> v; int mat_size; // 存储矩阵的边长 public: // 构造时传入运行时确定的大小 SMatrix(int n) : mat_size(n), v(n * n) {} T& operator() (int r, int c){ return v[mat_size * r + c]; } const T& operator()(int r, int c) const{ return v[mat_size * r + c]; } // 加个获取大小的方法方便后续使用 int size() const { return mat_size; } }; #endif
然后主函数里直接用读取到的M构造矩阵就行:
#include <fstream> #include <iostream> #include "T_SIMPLE_MATRIX_H" using namespace std; int main(int argc, char* argv[]) { ifstream fi(argv[1]); int N; fi >> N; for (int i = 0; i < N; i++) { int M; fi >> M; cout << "Matrix size " << M << endl; SMatrix<double> A(M); // 运行时传大小,完美解决问题 // 之后就可以正常用A(r,c)访问元素啦 } fi.close(); return 0; }
方案2:仅限固定几种大小的场景(不推荐通用)
如果你的矩阵大小只有有限的几种可能(比如只会是2、3、4),可以用std::variant来封装所有可能的模板实例,但这种方式灵活性极差,只适合特殊场景:
#include <variant> #include <iostream> #include <fstream> // 保留原来的模板类 template<class T, int N> class SMatrix { private: T v[N*N]; public: SMatrix<T, N>(){} T& operator() (int r, int c){ return v[N*r+c]; } const T& operator()(int r, int c) const{ return v[N*r+c]; } }; // 定义一个variant类型,包含所有可能的矩阵大小 using MatrixVariant = std::variant<SMatrix<double,2>, SMatrix<double,3>, SMatrix<double,4>>; MatrixVariant createMatrix(int M) { switch(M) { case 2: return SMatrix<double,2>(); case 3: return SMatrix<double,3>(); case 4: return SMatrix<double,4>(); default: throw std::invalid_argument("这个大小的矩阵不支持哦"); } } int main(int argc, char* argv[]) { ifstream fi(argv[1]); int N; fi >> N; for (int i = 0; i < N; i++) { int M; fi >> M; cout << "Matrix size " << M << endl; auto mat = createMatrix(M); // 使用的时候得用std::visit来访问variant里的具体对象 std::visit([](auto& m) { // 这里可以操作矩阵,比如m(0,0) = 1.0; }, mat); } fi.close(); return 0; }
这种方式的问题很明显——你得提前把所有可能的大小都列死,完全没法处理任意大小的矩阵,所以除非有特殊的性能需求且大小范围固定,否则别用这个。
总结
最靠谱的还是方案1:把模板的非类型参数去掉,改用std::vector动态存储,完美适配运行时确定大小的场景。模板非类型参数更适合那些编译期就能确定大小的场景,比如固定尺寸的数学矩阵(2x2、3x3)。
内容的提问来源于stack exchange,提问作者cppisnice
相关产品推荐
相关产品推荐

