C ++:不同类型模板函数的自定义返回值(方法)

时间:2016-12-19 01:50:59

标签: c++ c++11 templates

动机 - 在抽象数学中,我们可以将三维交叉积推广到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。如何以聪明的方式解决这个问题?

2 个答案:

答案 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行代码中。)