Sun*_*min 15 c++ templates template-meta-programming c++11
我想创建一个返回整数幂的函数.请阅读fmuecke 在c ++中的整数幂解决方案 .
但是,我想将他的解决方案推广到任意类型T.由于c ++ 11有constexpr,我想这是可能的.
天真,我尝试过类似的东西,
template<class T, int N>
inline constexpr T pow(const T x){
return pow<N-1>(x) * x;
}
template<class T>
inline constexpr T pow<T, 1>(const T x){
return x;
}
template<class T>
inline constexpr T pow<T, 0>(const T x){
return 1;
}
Run Code Online (Sandbox Code Playgroud)
实际上这种方法失败了,因为不允许对函数模板进行部分特化.
还有一个问题.我听说编译器是否在编译时评估constexpr函数是由编译器决定的.如何强制它计算一般类型.我从某处读到,对于整数consts来说,最简单的一个方法是将它包装在std :: integral_const :: value中.
dyp*_*dyp 22
使用递归的解决方案:
#include <iostream>
template<class T>
inline constexpr T pow(const T base, unsigned const exponent)
{
// (parentheses not required in next line)
return (exponent == 0) ? 1 : (base * pow(base, exponent-1));
}
int main()
{
std::cout << "pow(2, 4): " << pow(2, 4) << std::endl;
std::cout << "pow(5, 0): " << pow(5, 0) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
Jeremy W. Murphy通过平方建议/请求使用取幂的版本:
template<class T>
inline constexpr T pow(const T base, unsigned const exponent)
{
// (parentheses not required in next line)
return (exponent == 0) ? 1 :
(exponent % 2 == 0) ? pow(base, exponent/2)*pow(base, exponent/2) :
base * pow(base, (exponent-1)/2) * pow(base, (exponent-1)/2);
}
Run Code Online (Sandbox Code Playgroud)
"我听说编译器是否在编译时评估constexpr函数是由编译器决定的."
是的,AFAIK.编译器不需要在编译时进行常量初始化,但如果使用constexpr函数的结果作为非类型模板参数,则必须在编译时计算结果.
std::cout << std::integral_constant<int, pow(2, 4)>::value << std::endl;
Run Code Online (Sandbox Code Playgroud)
另请参阅使用方法integral_constant的参数pow在安迪四处寻觅的答案.
以下是如何强制执行编译时评估:
#include <iostream>
#include <type_traits>
// insert a constexpr `pow` implementation, e.g. the one from above
template < typename T, T base, unsigned exponent >
using pow_ = std::integral_constant < T, pow(base, exponent) >;
// macro == error prone, you have been warned
#define POW(BASE, EXPONENT) (pow_ < decltype(BASE), BASE, EXPONENT > :: value)
int main()
{
std::cout << "pow(2, 4): " << pow_<int, 2, 4>::value << std::endl;
std::cout << "pow(2, 4): " << POW(2, 4) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
如果你是downvote请发表评论,以便我可以改进我的答案.
And*_*owl 18
当你发现自己需要部分专门化功能模板时(注意,这并不意味着在这种情况下你需要,如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;
}
};
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以提供一个辅助函数模板,该模板委托给您的帮助器类模板的特化:
template<int N, class T>
T constexpr pow(T const x)
{
return detail::helper<T, N>::pow(x);
}
Run Code Online (Sandbox Code Playgroud)
这是一个实例.
编辑:
请注意,N == 1实际上并不需要专门化.我一直是在原来的文本,因为这个答案的目的主要是为了展示如何解决办法的部分专业函数模板是不可能在一般的 -所以我翻译的原程序片段逐件.
正如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;
}
};
}
Run Code Online (Sandbox Code Playgroud)
更新:
作为进一步的评论,请记住,即使您可以专门化功能模板(例如,使用显式 - 非部分 - 专业化),这通常不是一个好主意,因为功能模板专业化通常不像人们那样表现期望.
大多数可能似乎要求功能模板专业化的情况实际上可以通过重载实现,由标记调度等众所周知的技术提供支持.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>());
}
Run Code Online (Sandbox Code Playgroud)
但是,当真正需要时,应该考虑所有这些关于"如何解决似乎需要功能模板部分专业化的问题"的指导原则.在这个具体的案例中,正如DyP在他的回答中所表明的那样,他们不是.
这是一个具有单一功能的解决方案:
template <int N, class T>
constexpr T pow(const T& x)
{
return N > 1 ? x*pow<(N-1)*(N > 1)>(x)
: N < 0 ? T(1)/pow<(-N)*(N < 0)>(x)
: N == 1 ? x
: T(1);
}
Run Code Online (Sandbox Code Playgroud)