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>ます<limits>。したがって、たとえば、私は自分のシステムSizeInBits<char>::Resultに与えたいと思います。8SizeInBits<unsigned>::Result32

符号付き型での左ビット単位シフト演算子の有効性に関する注意:
コメントではFLAG << 1、オーバーフローが発生したときに符号付き型に対して が定義されているかどうかについて懸念がありました。この投稿で引用されている C++03 標準によると、それは定義されており、上記のアルゴリズムが期待することを実行します。

4

3 に答える 3

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

ニコラスのバージョンとは異なり、それはより単純で、警告を生成せず、実際に正しく機能します。

于 2012-10-01T18:08:01.517 に答える
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 に答える