我需要实现算法,使用模板递归计算两个向量的标量积。
有我的代码:
#include <iostream>
#include <vector>
template<typename T, int Size>
T scalar_product(const std::vector<T> &a, const std::vector<T> &b)
{
return a[Size - 1]*b[Size - 1] + (scalar_product<T, Size - 1>(a, b));
}
template<typename T>
T scalar_product<T, 0>(const std::vector<T> &a, const std::vector<T> &b) // error!
{
return a[0] * b[0];
}
int main()
{
std::vector<int> a(3, 1);
std::vector<int> b(3, 3);
std::cout << scalar_product<int, 3>(a, b);
return 0;
}
如果我使用此专业化T scalar_product<T, 0>(...)
,我会收到错误“'scalar_product':非法使用显式模板参数”。但是,如果我像这个T scalar_product(...)
编译器报告一样删除它,递归将是无限的(因为没有专业化,据我所知)。
这里有很多这类问题,但我找不到有用的答案。如何在不使用类的情况下专门化这个功能?先谢谢你了!
答案 0 :(得分:3)
有no partial function template specialization。您可以使用functor,这可以是部分专业化的:
template<typename T, int Size>
struct myFunctor
{
T scalar_product(const std::vector<T> &a, const std::vector<T> &b)
{
static_assert(Size > 0,"Size must be positive!")
return a[Size - 1]*b[Size - 1] + (myFunctor<typename T, Size - 1>::scalar_product(a, b));
}
};
template<typename T>
struct myFunctor<T,1>
{
T scalar_product(const std::vector<T> &a, const std::vector<T> &b)
{
return a[0] * b[0];
}
};
或者你可以使用std::enable_if来实现部分功能专业化。
template<typename T, int Size>
typename std::enable_if<(Size>1), T>::type scalar_product(const std::vector<T> &a, const std::vector<T> &b)
{
return a[Size - 1]*b[Size - 1] + (scalar_product<T, Size - 1>(a, b));
}
template<typename T, int Size>
T scalar_product(const std::vector<T> &a, const std::vector<T> &b, typename std::enable_if<(Size == 1), void*>::type x = nullptr)
{
return a[0] * b[0];
}
请注意,我在2个函数中使用了两种不同的方法来使用std :: enable_if,以表明两者都是可能的。两个函数都可以像第一个函数一样在返回类型上使用enable_if,并且它们都可以像第二个函数那样在参数上使用它们。如需更多阅读,请参阅SFINAE。
或者作为第三个选项,你可以像这样处理函数内部的特化:
template<typename T, int Size>
T scalar_product(const std::vector<T> &a, const std::vector<T> &b)
{
static_assert(Size > 0,"Size must be positive!")
if (Size==1)
return a[0] * b[0];
return a[Size - 1]*b[Size - 1] + (scalar_product<T, (Size==1) ? Size : Size - 1>(a, b));
}
请注意,如果没有(Size==0) ? Size : Size - 1
,编译器将为int的所有值创建一个函数,或者尝试死。