当您发现自己需要部分专门化功能模板时(请注意,这并不意味着在这种情况下您需要,正如DyP 的回答所示),您可能会诉诸重载(请参阅本文末尾的最后更新答案),或者,如果不可能,将该函数模板包装到类模板中,并用一个静态的非模板成员函数替换您的原始函数模板(及其特化):
namespace detail
{
template<class T, int N>
struct helper
{
static constexpr T pow(const T x){
return helper<T, N-1>::pow(x) * x;
}
};
template<class T>
struct helper<T, 1> // Unnecessary specialization! (see the edit)
{
static constexpr T pow(const T x){
return x;
}
};
template<class T>
struct helper<T, 0>
{
static constexpr T pow(const T x){
return 1;
}
};
}
然后,您可以提供一个辅助函数模板,该模板代表您的辅助类模板的特化:
template<int N, class T>
T constexpr pow(T const x)
{
return detail::helper<T, N>::pow(x);
}
这是一个活生生的例子。
编辑:
N == 1
请注意,实际上不需要专门化 for 。我将其保留在原始文本中,因为此答案的目的主要是说明如何解决通常无法部分专门化功能模板的问题-因此我逐段翻译了原始程序。
然而,正如 Dyp在评论中指出的那样,这就足够了:
namespace detail
{
template<class T, int N>
struct helper
{
static constexpr T pow(const T x){
return helper<T, N-1>::pow(x) * x;
}
};
template<class T>
struct helper<T, 0>
{
static constexpr T pow(const T x){
return 1;
}
};
}
更新:
作为进一步说明,请记住,即使您可以特化函数模板(例如,使用显式 - 不是部分 - 特化),这样做通常也不是一个好主意,因为函数模板特化通常不会表现得像预计。
大多数看起来需要函数模板特化的情况实际上可以通过重载来实现,由标记调度等众所周知的技术提供支持。Potatoswatter在评论中提出了一个例子,指出std::integral_constant
可以在这种情况下使用:
template<class T>
inline constexpr T pow(const T x, std::integral_constant<T, 0>){
return 1;
}
template<class T, int N>
inline constexpr T pow(const T x, std::integral_constant<T, N>){
return pow(x, std::integral_constant<T, N-1>()) * x;
}
template<int N, class T>
inline constexpr T pow(const T x)
{
return pow(x, std::integral_constant<T, N>());
}
但是,所有这些关于“如何解决似乎需要函数模板部分专业化的问题”的指导方针都应该在真正需要时加以考虑。在这个具体案例中,正如 DyP 在他的回答中所表明的那样,事实并非如此。