C++ 模板函数递归定义的消歧

C++ 模板函数递归定义的消歧,c++,templates,C++,Templates,我正在构建一个静态类型的矩阵,其中所有与矩阵相关的操作都要进行类型检查。然而,当我想根据给定的数字修改矩阵时,我遇到了一些问题 例如,添加一列非常简单: template<int A, int B> Matrix<A,B+1> addOneCol(Matrix<A,B> m1) { return Matrix<A,B+1>(); } 模板 矩阵addOneCol(矩阵m1){ 返回矩阵(); } 但是,添加N列要困难得多。由于无法使用具

我正在构建一个静态类型的矩阵,其中所有与矩阵相关的操作都要进行类型检查。然而,当我想根据给定的数字修改矩阵时,我遇到了一些问题

例如,添加一列非常简单:

template<int A, int B>
Matrix<A,B+1> addOneCol(Matrix<A,B> m1) {
    return Matrix<A,B+1>();
}
模板
矩阵addOneCol(矩阵m1){
返回矩阵();
}
但是,添加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(矩阵m1){
返回addOneCol(m1);
}
样板
矩阵addZCols(矩阵m1){
返回addOneCol(addZCols(m1));
}
样板
矩阵addOneCol(矩阵m1){
返回矩阵();
}
但是,这是在返回类型中重载了
addZCols
,这是不允许的,并导致一个错误,即调用
addZCalls
是不明确的,不能选择两个候选项中的一个。我想要的是,只有当
Z=1
时,才将具有
B+1
的版本称为基本情况


有没有关于如何使这项工作或其他方法的想法?

可能有一种更有效的方法,但使用您提出的递归解决方案,可以用来消除模板函数的两个版本之间的歧义

#包括
样板
结构矩阵{
constexpr int rows()const{return A;}
constexpr int cols()const{return B;}
int数据;
};
样板
矩阵addZCols(矩阵m1){
返回m1;
}
样板
矩阵addZCols(矩阵m1){
返回addOneCol(addZCols(m1));
}
样板
矩阵addOneCol(矩阵m1){
返回矩阵();
}
int main(){
矩阵m1;
自动m2=addZCols(m1);
静态_断言(m2.rows()==2,“检查行”);
静态_断言(m2.cols()==5,“检查cols”);
返回0;
}

为了清晰起见,我还将递归限制偏移了1,并对
addZCols
的模板参数进行了重新排序,以使调用更方便,但它与原始签名的效果相同。

可能有一种更有效的方法,但使用您提出的递归解决方案,可用于消除模板函数的两个版本之间的歧义

#包括
样板
结构矩阵{
constexpr int rows()const{return A;}
constexpr int cols()const{return B;}
int数据;
};
样板
矩阵addZCols(矩阵m1){
返回m1;
}
样板
矩阵addZCols(矩阵m1){
返回addOneCol(addZCols(m1));
}
样板
矩阵addOneCol(矩阵m1){
返回矩阵();
}
int main(){
矩阵m1;
自动m2=addZCols(m1);
静态_断言(m2.rows()==2,“检查行”);
静态_断言(m2.cols()==5,“检查cols”);
返回0;
}

为了清晰起见,我还将递归限制偏移了1,并对
addZCols
的模板参数进行了重新排序,以使调用更方便,但它与原始签名的效果相同。

如果我正确理解您的要求,您可以简单地编写如下函数模板:

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>{});
Matrix<1,2> a = addZCols(Matrix<1,1>{});

Matrix<1,4> b = addZCols<3>(Matrix<1,1>{});
这样您可以更方便地拨打电话,如下所示:

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>{});
Matrix<1,2> a = addZCols(Matrix<1,1>{});

Matrix<1,4> b = addZCols<3>(Matrix<1,1>{});
矩阵a=addZCols(矩阵{});
矩阵b=addZCols(矩阵{});

因为只需要指定
Z
,因为
A
B
可以从
矩阵
参数中推导出来。

如果我正确理解了您的需求,您可以这样简单地编写函数模板:

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>{});
Matrix<1,2> a = addZCols(Matrix<1,1>{});

Matrix<1,4> b = addZCols<3>(Matrix<1,1>{});
这样您可以更方便地拨打电话,如下所示:

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>{});
Matrix<1,2> a = addZCols(Matrix<1,1>{});

Matrix<1,4> b = addZCols<3>(Matrix<1,1>{});
矩阵a=addZCols(矩阵{});
矩阵b=addZCols(矩阵{});

因为只需要指定
Z
,因为
A
B
可以从
Matrix
参数中推导出来。

我已经读了好几遍这个问题,但仍然无法理解问题所在。@Evg问题在于代码没有编译,错误在于它无法消除Matrix addZCols之间的歧义(矩阵m1)和矩阵addZCols(矩阵m1)这个问题我已经读了好几遍了,但还是不明白问题是什么。@Evg问题是代码没有编译,错误是它不能消除矩阵addZCols(矩阵m1)和矩阵addZCols(矩阵m1)之间的歧义非常感谢您的建议!我不知道SFINAE,但我确实在寻找某种方法来约束模板参数的值。出于好奇,您对如何处理此问题有什么其他建议吗?正如您所指出的,它可能效率低下,但我无法找到比打字检查更好的方法。我的直觉是,由于这些类型检查和基于模板的计算发生在编译时,因此运行时性能实际上应该是良好的。不过编译时间可能会增加。要检查这种直觉,我将查看程序生成的程序集,并检查此类型检查是否引入意外开销。谢谢非常感谢您的建议!我不知道SFINAE,但我确实在寻找某种方法来约束模板参数的值。出于好奇,您对如何处理此问题有什么其他建议吗?正如您所指出的,它可能效率低下,但我没有比打字检查更好的方法。我的直觉值得注意的是,由于这些类型检查和基于模板的计算发生在编译时,运行时性能实际上应该是良好的。不过编译时间可能会增加。为了检查这种直觉,我会查看程序生成的程序集,并检查这种类型检查是否会引入意外开销。为什么不进行
Z
第一个参数,然后只写
addZCols(…)
?这很好,只是它不能有一个默认值。为什么不呢?
a
B
可以从
矩阵
中推导出来,所以可以添加一个默认的v