2

通过解决各种玩具问题,我开始熟悉元编程。这是一个让我难过的问题:如何编写一个元程序,以位为单位提供整数类型参数的大小。特别是,我想在没有CHAR_BIT或任何其他幻数的情况下做到这一点。

我从以下非元程序开始:

template <typename T>
int sizeInBits(void) {
    T flag = 1;
    int count = 0;
    while (flag != 0) {
        flag <<= 1;
        ++count;
    }
    return count;
}

转换为元程序,我认为它看起来像这样:

template<typename T, int COUNT = 0, T FLAG = 1>
struct SizeInBits {
    enum {Result = SizeInBits<T, COUNT + 1, FLAG << 1 >::Result};
};

template<typename T, int COUNT>
struct SizeInBits<T, COUNT, 0> {
    enum {Result = COUNT};
};

但是,该程序无法编译,因为显然专注于具有模板参数类型的非类型模板参数是非法的,因此我使用 gcc 4.6 收到以下错误消息:

error: type ‘T’ of template argument ‘0’ depends on a template parameter

有任何想法吗?

编辑
我本质上是在寻找与<climits>and中的幻数等效的元程序<limits>。因此,例如,我想在我的系统上给予,SizeInBits<char>::Result并给予.8SizeInBits<unsigned>::Result32

关于有符号类型的左移运算符有效性的注意事项
在评论中,当溢出发生时,是否FLAG << 1为有符号类型定义了一些问题。根据这篇文章中引用的 C++03 标准,它被定义并执行上述算法所期望的。

4

3 回答 3

2

非类型模板实参的类型不能依赖于偏特化的模板形参。编译器将不允许以下部分特化:

template <class T, T t> class X { };

// Invalid partial specialization
template <class T> class X<T, 25> { };

为了解决这个问题,您可以使用int FLAG

#include <iostream> 

template<typename T, int COUNT = 0, int FLAG = 1>
struct SizeInBits {
    enum { 
        Result = SizeInBits<T, COUNT + 1, FLAG << 1>::Result
    };
};

template<typename T, int COUNT>
struct SizeInBits<T, COUNT, 0> {
    enum {
        Result = COUNT
    };
};

int main() {
   std::cout << SizeInBits<int, 10>::Result << std::endl;
}

但似乎你需要sizeof(T) * CHAR_BIT或喜欢这样:

#include <iostream> 
#include <climits>

template<typename T>
struct SizeInBits {
    enum { 
        Result = sizeof(T) * CHAR_BIT
    };
};

int main() {
   std::cout << SizeInBits<long>::Result << std::endl;
}
于 2012-10-01T05:47:07.367 回答
2

那这个呢:

template<typename T, int COUNT = 0, int FLAG = 1>
struct SizeInBits {
    enum {Result = SizeInBits<T, COUNT + 1, static_cast<T>(FLAG) << 1 >::Result};
};

template<typename T, int COUNT>
struct SizeInBits<T, COUNT, 0> {
    enum {Result = COUNT};
};

它对我有用。

于 2012-10-01T06:11:15.267 回答
2

这应该可以解决问题:

template<typename T, unsigned long long flag = 1uLL>
struct bits_in {
    enum {value = 1 + bits_in<T, (unsigned long long)(T)(flag << 1)>::value};
};

template<typename T>
struct bits_in<T, 0uLL> {
    enum {value = 0};
};

Nicolas 的版本不同,它更简单,不会产生警告,并且实际上可以正常工作

于 2012-10-01T18:08:01.517 回答