使用模板元编程来计算整数中的设置位数的问题

时间:2014-08-10 00:01:13

标签: c++

作为一个实验,我正在尝试编写模板代码来计算编译时整数中的设置位数。这是我的第一次尝试:

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中的错误还是我的代码中的错误?

谢谢!

3 个答案:

答案 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;
};

Live example

或只是一个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));
}