我正在构建一个静态类型的Matrix,其中所有带有矩阵的操作都经过类型检查。但是,当我想做一些基于给定数字修改矩阵的事情时,我会遇到问题。
例如,添加一列很简单:
template<int A, int B>
Matrix<A,B+1> addOneCol(Matrix<A,B> m1) {
return Matrix<A,B+1>();
}
但是,添加N列要困难得多。由于不可能使用具有分支的函数进行类型检查,而分支的返回类型不是预期的(即使分支条件可以保证),所以我只能考虑一种递归方法:
template<int A, int B, int Z>
Matrix<A,B+1> addZCols(Matrix<A,B> m1) {
return addOneCol(m1);
}
template<int A, int B, int Z>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return addOneCol(addZCols<A,B,Z-1>(m1));
}
template<int A, int B>
Matrix<A,B+1> addOneCol(Matrix<A,B> m1) {
return Matrix<A,B+1>();
}
但是,这在返回类型中重载了addZCols
,这是不允许的,并导致错误,导致呼叫addZCalls
的过程很模糊,无法选择2个候选者之一。我想要的是,B+1
的版本仅被称为基本情况,可以说是Z=1
时的情况。
关于如何进行这项工作或采用其他方法的任何想法吗?
答案 0 :(得分:2)
如果我正确理解了您的要求,则可以简单地编写如下功能模板:
mx-auto
然后像这样使用它:
template<int A, int B, int Z = 1>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return Matrix<A,B+Z>{};
}
默认情况下,第三个参数是Matrix<1,2> a = addZCols(Matrix<1,1>{});
Matrix<1,4> b = addZCols<1,1,3>(Matrix<1,1>{});
,因此该功能模板可以用作1
。
@Evg指出,模板参数具有不错的属性,默认参数可以按任何顺序出现,因此我们可以将addOneCol
参数放在第一个位置:
Z
这使您可以更方便地拨打电话,如下所示:
template<int Z = 1, int A, int B>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return Matrix<A,B+Z>{};
}
由于只需要指定Matrix<1,2> a = addZCols(Matrix<1,1>{});
Matrix<1,4> b = addZCols<3>(Matrix<1,1>{});
,因为Z
,并且可以从A
参数推导出B
。
答案 1 :(得分:1)
也许有一种更有效的方法,但是使用您建议的递归解决方案,SFINAE可用于消除模板功能的两个版本的歧义。
#include <type_traits>
template <int A, int B>
struct Matrix {
constexpr int rows() const { return A; }
constexpr int cols() const { return B; }
int data;
};
template<int Z, int A, int B, std::enable_if_t<Z == 0, int> = 0>
Matrix<A, B> addZCols(Matrix<A,B> m1) {
return m1;
}
template<int Z, int A, int B, std::enable_if_t<Z != 0, int> = 0>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return addOneCol(addZCols<Z-1, A, B>(m1));
}
template<int A, int B>
Matrix<A,B+1> addOneCol(Matrix<A,B> m1) {
return Matrix<A,B+1>();
}
int main() {
Matrix<2, 2> m1;
auto m2 = addZCols<3>(m1);
static_assert(m2.rows() == 2, "check rows");
static_assert(m2.cols() == 5, "check cols");
return 0;
}
为了清楚起见,我也将递归限制偏移了一个,并对addZCols
的模板参数进行了重新排序,以使其调用起来更好,但是它与原始签名的作用相同。