C++ 部分特化不适用于不同大小的特征矩阵

C++ Partial Specialization Not Working for Differing Size Eigen Matrices

本文关键字:特征 适用于 不适用 C++      更新时间:2023-10-16

在过去的几个小时里,我一直在撞墙,试图弄清楚为什么一些部分模板专业化失败了,我真的可以使用一些帮助。

基本上,我正在处理一些依赖于在编译时了解矩阵大小的代码,但我正在尝试使用模板来做。使用类型组合似乎存在某种我真的不明白的问题。为了说明,请考虑以下(稍微毫无意义的(代码:

template <typename T> struct type1 { typedef bool bar; };
template <typename T, int R, int C> struct type1<Matrix<T, R, C>> { typedef Matrix<T, R, C> bar; };
template <typename T1, typename T2> struct type2 { typedef bool bar; };
template <typename T, int R, int M, int C> struct type2<Matrix<T, R, M>, Matrix<T, M, C>> { typedef Matrix<float, 2, 2> bar; };
template <typename T1, typename T2> struct type3 { typedef bool bar; };
template <typename T, int R, int M, int C> struct type3<Matrix<T, R, M>, Matrix<T, M, C>> { typedef Matrix<T, R, C> bar; };
template <typename T> struct Test {
static bool foo() {
return false;
}
};
template <typename T, int R, int C> struct Test<Matrix<T, R, C>> {
static bool foo() {
return true;
}
};

我对模板组合的理解是,这些模板应该能够以如下所示的方式组合,其中每一行都应返回 true。但请注意,最后两个返回 false。

/* true  <- */  Test<Matrix<float, 2, 2>>::foo();
/* true  <- */  Test<Matrix<float, 6, 3>>::foo();
/* true  <- */  Test<type1<Matrix<float, 2, 7>>::bar>::foo();
/* And so on for any other size . . . */
/* true  <- */  Test<type2<Matrix<float, 3, 3>, Matrix<float, 3, 3>>::bar>::foo();
/* true  <- */  Test<type3<Matrix<float, 2, 2>, Matrix<float, 2, 2>>::bar>::foo();
/* And so on for any other pair of square sizes . . . */
/* false <- */  Test<type2<Matrix<float, 2, 3>, Matrix<float, 3, 2>>::bar>::foo();
/* false <- */  Test<type3<Matrix<float, 2, 4>, Matrix<float, 4, 1>>::bar>::foo();
/* And so on for any other pair of non-square sizes . . . */

特别奇怪的是,当我用任意template <typename T, int R, int C> struct Thing替换Eigen::Matrix时,一切都按预期工作(即所有测试都返回 true(,这就是为什么我认为这个问题特定于特征矩阵。


编辑:实际上,这似乎与我在MSVC上构建的事实有关(在2015年和2017年都失败了(。当我在 g++ 或 clang 上编译它时,它工作正常。更多证据表明Visual C++是一个真正的混乱(并不是说它真的需要(。

此外,它似乎实际上与两个参数具有不同大小的情况有关。例如:

template <typename T1, typename T2> struct typetest { typedef bool bar; };
template <typename T, int R1, int C1, int R2, int C2> struct typetest<Matrix<T, R1, C1>, Matrix<T, R2, C2>> { typedef Matrix<float, 2, 2> bar; };

当第一个和第二个矩阵类型具有相同的大小时,此操作会成功,但在它们不同时会失败。例如:

/* true  <- */  Test<typetest<Matrix<float, 2, 3>, Matrix<float, 2, 3>>::bar>::foo();
/* true  <- */  Test<typetest<Matrix<float, 6, 1>, Matrix<float, 6, 1>>::bar>::foo();
/* false <- */  Test<typetest<Matrix<float, 2, 2>, Matrix<float, 2, 3>>::bar>::foo();
/* false <- */  Test<typetest<Matrix<float, 5, 3>, Matrix<float, 2, 4>>::bar>::foo();

不幸的是,由于一些非常烦人的依赖关系,我暂时主要停留在 MSVC,所以我需要一个解决方法。有人有什么想法吗?

为了使其完整,@chtz在上面的评论中建议的解决方案完全适用于MSVC 2015和2017。通过问题中特定不同大小问题的示例,这非常有效:

template <typename T1, typename T2> struct typen { typedef bool bar; };
template <typename T, int R, int M, int C, int O1, int O2, int Rc1, int Rc2, int Cc1, int Cc2>
struct typen<Matrix<T, R, M, O1, Rc1, Cc1>, Matrix<T, M, C, O2, Rc2, Cc2>> { typedef Matrix<T, R, C> bar; };
...
/* true :-) */  Test<typen<Matrix<float, 2, 3>, Matrix<float, 3, 4>>::bar>::foo();