动机 - 在抽象数学中,我们可以将三维交叉积推广到n维,假设对于维v,w
的两个向量n
,它们的叉积将具有维n(n-1)/2
。跳过差异表单的想法,我想将这个想法转换为C ++库中的模板语言。我有这个想法:
auto Cross(const Vec<dim, float_t> &rhs) {
if (dim == 0)return;
if (dim == 1)return (float_t)0;
if (dim == 2)return Values[0] * rhs.Values[1] - Values[1] * rhs.Values[0];
if (dim == 3)return Vec<dim, float_t>(
Values[1] * rhs.Values[2] - Values[2] * rhs.Values[1],
Values[2] * rhs.Values[0] - Values[0] * rhs.Values[2],
Values[0] * rhs.Values[1] - Values[1] * rhs.Values[0]);
//...
}
但遗憾的是,auto
说明符并不允许不同的返回类型。我当然可以使用预处理器,但我相信有更聪明的方法可以做到这一点,例如:
Vec<dim*(dim-1)/2,float_t> Cross(const Vec<dim,float_t> &rhs);
(void
作为零维点的特例,而一维点只是float_t
。如何以聪明的方式解决这个问题?
答案 0 :(得分:3)
我相信你可以这样做:
template <std::size_t dim>
auto cross(const Vec<dim, float_t>& rhs)
{
/*logic goes here, also you can generalize*/
}
这将为每个dim
创建新函数(隐式)。此外,尝试使用特化在编译时而不是运行时执行此操作。
答案 1 :(得分:1)
实现这一目标的一种方法是通过专业化。如果没有专业化,那么实现真正通用的模板算法将非常困难(我有兴趣看到)。
如果使用特化,大多数情况下都不能使用auto
,则返回类型必须是显式的。这应该做你想要的:
#include<cassert>
#include<array>
using std::array;
template<std::size_t Dim>
array<double, Dim*(Dim-1)/2>
Cross(array<double, Dim> const&, array<double, Dim> const&);
template<> array<double, 0> Cross(
array<double, 1> const&, array<double, 1> const& v2
){return {};}
template<> array<double, 1> Cross(
array<double, 2> const& v1, array<double, 2> const& v2
){return {{v1[0] * v2[1] - v1[1] * v2[0]}};}
template<> array<double, 3> Cross(
array<double, 3> const& v1, array<double, 3> const& v2
){
return {{
v1[1] * v2[2] - v1[2] * v2[1],
v1[2] * v2[0] - v1[0] * v2[2],
v1[0] * v2[1] - v1[1] * v2[0]
}};
}
int main(){
array<double, 1> v1{{1.}};
array<double, 2> v2{{1.,2.}};
array<double, 3> v3{{1.,2., 3.}};
assert(( Cross(v1, v1) == array<double, 0>{} ));
assert(( Cross(v2, v2)[0] == 0. ));
assert(( Cross(v3, v3)[0] == 0. ));
}
现在,如果你知道你将使用(总)特化(如上所述),那么Cross
的这个和单独的重载之间几乎没有区别(除了强制执行某个特定的返回类型在第6行代码中。)