次のフラグメントは、T 型の (符号なしと想定される) 整数の次に高い 2 の累乗を返します。これは、ビットを繰り返しシフトすることによって行われます。
すべての意図と目的のために、ビット シフト ループで使用される符号なし型 i は、(名目上) 65536 ビット数を表すのに十分な大きさです。したがって、実際には「そのまま」のままで問題ありません。
template <class T>
T supremum_2(T k) {
if (k == T(0)) return T(1);
k--;
for (int i=1; i<sizeof(T)*8; i++) k |= k >> i;
return k+1;
}
プロフェッショナルな仕事をするには、オーバーフローなしで sizeof(T)*8 までスパンできることが保証されるように、コンパイル時にループ カウンターの型を選択する必要があります。
std::numeric_traits を使用してコンパイル時にこれを実行できますか? もしそうなら、どのように?
概念的には、次のようなものを書きたいと思います。
typedef unsigned_type_that_can_represent<sizeof(T)*8> counter_type;
...
...
for (counter_type i(1); i<sizeof(T)*8; i<<=1) k = k | k >> i;
...
以下の議論に基づいて、次のコンテキストを追加することにしました。
別の言い方をすれば:
コンパイル時にテンプレート コードの内部動作に効率的 (必要な大きさのみ) で適切な型を選択することを保証するにはどうすればよいでしょうか? テンプレートコードで具象型を使用していることに気付いた場合、潜在的に不透明なルートを介してテンプレートの型について不注意に仮定している可能性があります。
たとえば、カウンターに int を (たとえば) 使用する場合、誰かがそのテンプレート コードを bigint ライブラリで使用するまでは、すべて正常に機能します。これは、int で表現できるよりも多くの 2 進数で整数を表すことができます。したがって、型を unsigned long long にする必要がありますか? 確かに、それは問題を遅らせるだけですか (長い間ではありますが)? このソリューションには、「640K - 誰にとっても十分な大きさ」または静的配列サイズの色合いがあります。
この場合の明らかな、しかしやや非効率的な選択は、カウンターの型を数値 k の型と同じに設定することです。カウンタが k のビット数に対応する数を表すことができることのみを要求するため、(原則として) 非効率的です。他の状況では、これを想定するのは間違っているかもしれません。
一般的な場合はどうですか?メタプログラミングが適切なアプローチであるように見えます。この「正気」を保つ方法は?おそらく、正式には、コンパイル時の関数が (派生する可能性がある) 抽象型の要件を型にマップすることが要件です。
おそらく、YABL (Yet Another Boost Library) の仕事でしょう!
【乱文失礼します】