ここで 2 つの質問があります。
1つは、あなたが話している値だけを含む関数の引数と戻り値などに関するものです。これらが1文字未満になることはありません。そして、実際には、整数よりも少ないスペースを使用することは、ほとんどの場合、あまり役に立ちません。
もう一つは収納についてです。クラスのメンバーとしてのストレージ、またはこれらの値のある種のコレクション。そこでは、さまざまなテクニックやトリックを使用して、1 バイトもかからないようにすることができます。
実際、それらの大きなコレクションがある場合、または値の範囲が非常に制限された他の多くのタイプと組み合わせてデータ構造にそれらを格納する必要がある場合は、それらにほんの少しの割合を占めることさえできます。これには、スペースを共有するより大きなデータ型から値を抽出するための CPU のトレードオフが伴います。しかし、それは可能です。
ある程度、この狭い範囲の値を他の値と同じ組み合わせで常に渡している場合は、関数の引数の問題をストレージの問題に変えることができます。ただし、引数として直接渡す必要がある場合は、これを行うことはできません。
用途ごとにこの型を定義する方法の例をいくつか簡単に投稿します。
値の受け渡しについては、この回答にそれがあります。を使用しenum
ます。enum
C++11 では、を で可能な限り最小のデータ型として表現することを選択できますenum Foo : char { Val1, Val2, Val3 };
。
それらの配列全体を保存するには、次の手法を使用できます。
#include <limits>
enum Foo : char { Val1, Val2, Val3 };
template <unsigned int NumFoos>
class FooArray {
static constexpr unsigned int foos_in_x(unsigned long long x) noexcept(true) {
return (x > 3) ? (1 + foos_in_x(x / 3)) : 0;
}
static constexpr unsigned int foos_per_ll = foos_in_x(::std::numeric_limits<unsigned long long>::max());
static constexpr unsigned long long array_size() noexcept(true) {
return (NumFoos + (foos_per_ll - 1)) / foos_per_ll;
}
static constexpr unsigned int div_value(unsigned int n) {
return (n == 0) ? 1 : (3 * div_value(n - 1));
}
public:
explicit FooArray(Foo defaultval = Val1);
~FooArray();
Foo operator[](unsigned long long pos) const {
const unsigned long long arypos = pos / foos_per_ll;
const unsigned int fooval = (foovals_[arypos] / div_value(pos % foos_per_ll)) % 3;
return (fooval == 0) ? Val1 : ((fooval == 1) ? Val2 : Val3);
}
private:
unsigned long long foovals_[array_size()];
};
もちろん、非 constoperator []
は、割り当てられている場合に配列内の適切な値をいじる特別な参照型を返す必要があります。その方法がわかりにくい場合は、代入関数がどのように機能するかの例を書くことができます。これは、非 const から::std::bitset
型を返す方法に似ています。reference
operator []