作为一个实验,我正在尝试编写模板代码来计算编译时整数中的设置位数。这是我的第一次尝试:
template<unsigned long long x>
struct BitCount
{
static const int result = (x == 0) ? 0 : ((x & 1) + BitCount<(x >> 1)>::result);
};
这会产生错误。
Visual Studio 2013
error C2065: 'result' : undeclared identifier
ideone.com
error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) instantiating ‘BitCount<0ull>::result’
如何正确修复此错误?
好的,所以我把它改成了
#include <iostream>
using namespace std;
template<unsigned long long x>
struct BitCount
{
static const int result;
};
template<unsigned long long x>
const int BitCount<x>::result = (x == 0) ? 0 : ((x & 1) + BitCount<(x >> 1)>::result);
template<unsigned long long x>
int bitcount()
{
return BitCount<x>::result;
}
int main()
{
cout << bitcount<5>() << endl;
cout << bitcount<1>() << endl;
cout << bitcount<3>() << endl;
cout << bitcount<0>() << endl;
return 0;
}
ideone.com正确输出:2 1 2 0
Visual Studio 2013输出错误:1 1 2 0
这是VS中的错误还是我的代码中的错误?
谢谢!
答案 0 :(得分:4)
您需要专门化零终止案例:
template<>
struct BitCount<0>
{
static const int result = 0;
};
否则,您只需依赖主模板,以便将BitCount<0>::result
定义为true ? 0 : BitCount<0>::result
,这是一个无休止的递归模板实例化。即使它没有被评估,它仍然需要实例化else子句。
答案 1 :(得分:2)
您需要专门研究基本情况,或者在那里获得无限的编译时递归(基本情况的定义取决于基本情况的定义)。
此外,如果你内联初始化它看起来更好:
template<unsigned long long x>
struct PopCount
{
static const int result = (x&1)+BitCount<(x>>1)>::result;
};
template<>
struct PopCount<0ULL>
{
static const int result = 0;
}
BTW:使用constexpr
代替const static
而不是constexpr int popCount(unsigned long long x) {
return x ? int(x&1) + popCount(x>>1) : 0;
}
更好,更好的是函数(C ++ 11):
constexpr int popCount(unsigned long long x) {
int r = 0;
for(; x; x &= x-1)
++r;
return r;
}
作为最后一步,在运行时执行它时,使函数迭代以获得更好的性能(C ++ 14)。
x &= x-1;
此赋值{{1}}清除最低位设置位,因此需要的迭代次数更少。
答案 2 :(得分:1)
您可以使用以下内容:
template<unsigned long long x>
struct BitCount
{
static constexpr const int result = (x & 1) + BitCount<(x >> 1)>::result;
};
template<>
struct BitCount<0>
{
static constexpr const int result = 0;
};
或只是一个constexpr功能
constexpr int bitCount(unsigned long long x)
{
return (x == 0) ? 0 : int(x & 1ULL) + bitCount(x >> 1);
}
顺便说一句,您可以使用位技巧x & (x-1)
来屏蔽最低设置位,而不是执行x >> 1
,如下所示:
constexpr int bitCount(unsigned long long x)
{
return (x == 0) ? 0 : 1 + bitCount(x & (x - 1));
}