c++ power of integer,模板元编程
c++ power of integer, template meta programming
我想创建一个返回整数幂的函数。请读一读这个问题的解决方案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;
}
实际上这种方法失败了,因为函数模板的部分特化是不允许的。
还有一个问题。我听说constexpr函数是否在编译时进行评估取决于编译器。我如何强制它为一般类型计算。我从某个地方读到,整型const最简单的方法之一是将其封装在std::integral_const::value中。
递归解:
#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;
}
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);
}
"我听说constexpr函数是否在编译时求值取决于编译器。"
真的,AFAIK。编译器不需要在编译时进行常量初始化,但如果您将constexpr函数的结果用作非类型模板参数,则编译器必须在编译时计算结果。
std::cout << std::integral_constant<int, pow(2, 4)>::value << std::endl;
参见Andy Prowl回答中使用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;
}
如果你不喜欢,请留下评论,这样我可以改进我的答案。
当您发现自己需要部分专门化函数模板时(注意,这并不意味着在这种情况下您需要,正如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
的专门化实际上是不必要的。我把它保留在原文中,因为这个答案的目的主要是展示如何解决一般不可能部分专门化的函数模板的问题,所以我一点一点地翻译了原始程序。
正如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<int, 0>){
return 1;
}
template<class T, int N>
inline constexpr T pow(const T x, std::integral_constant<int, N>){
return pow(x, std::integral_constant<int, N-1>()) * x;
}
template<int N, class T>
inline constexpr T pow(const T x)
{
return pow(x, std::integral_constant<int, N>());
}
然而,所有这些关于"如何解决似乎需要函数模板部分专门化"的问题的指导方针;在真正需要的时候应该加以考虑。在这个具体的例子中,正如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);
}
有一个简单的解决方案:
#include<bits/stdc++.h>
using namespace std;
template<int N, int M>
struct Pow
{
enum { res = N * Pow<N,M-1>::res};
};
template<int N>
struct Pow<N,0>
{
enum {res = 1};
};
int main()
{
cout<<Pow<2,3>::res<<"n";
}
简单明了的解决方案:
#include <cstddef>
template<size_t N, size_t P>
struct pow_constexpr { constexpr static auto value = N * pow_constexpr<N, P-1>::value; };
template<size_t N>
struct pow_constexpr<N, 1> { constexpr static auto value = N; };
template<size_t N>
struct pow_constexpr<N, 0> { constexpr static auto value = 1; };
int main() {
return pow_constexpr<2, 30>::value; // 1073741824
}
- 有一个打印语句的函数是一种糟糕的编程实践吗
- 我是C++编程的新手,这些代码之间有什么区别,我应该使用哪一个
- 模板元编程:如何将参数包组合成新的参数包
- Qt Q串行端口未编程设备未关闭
- 模板元编程 - 尝试实现维度分析
- 我是编程新手
- C++编程从外部文本文件定义数组大小
- 了解算法的性能差异(如果以不同的编程语言实现)
- 使用 Gtkmm 以编程方式选择 Gtk::TextView 中的文本
- 如何将可变参数模板转换为多个单个模板?(C++竞争编程调试模板)
- 使用命名空间正确编程
- C++编程:运算符重载中的引用如何工作?
- Arduino 模块化编程与全局和设置
- C++ 运算符修改/元编程策略,用于不那么冗长的语法
- 在没有管理员权限的情况下,在 c++ 中以编程方式将程序添加到启动
- 如何以编程方式将音频从任何录制设备路由到任何播放设备
- 试图修复一个错误,该错误不会让我开始编程其余部分
- C++模板编程设计问题 - 根据输入文件返回不同的类型
- Frank Luna 在他的书"使用 DirectX12 进行 3D 游戏编程"的介绍中盒子示例的问题
- c++ power of integer,模板元编程