コンパイル時に配列の最大数を計算する

こんにちは、Habr!



少し前までは、コンパイル段階でいくつかの特定の行の最大長を計算する必要がありました。 char []配列にメモリを割り当てて、指定された文字列がそれに適合するようにする必要があります。 システムが適切に設計されていれば、コンパイル段階で計算は不要であり、std :: auto_ptrまたはstd :: stringを使用して動的割り当てを使用できると仮定するのは論理的ですが、そうではありません。 char []バッファーが格納される構造は、PODタイプでなければなりません。



基本的に、タスクは、コンパイル段階で配列の最大数を決定することに要約されます。 このトピックでは、c ++ 03およびc ++ 11標準でこれを行う方法を示します。 解決策を探しているときに、問題の解決に役立つ2つの記事を見つけました: habrahabr.ru/post/166201、habrahabr.ru/post/38622



したがって、指定されたすべての行を回避するには、それらを配列に追加します。

const char str1[] = "Anna"; const char str2[] = "Denis"; const char str3[] = "Vladimir"; const char str4[] = "Alexey"; const char *arr[] = { str1, str2, str3, str4 };
      
      





現在、sizeof(arr)は16を返し、sizeof(arr [2])は4を返します。 コンパイル段階では、ポインターの逆参照操作は許可されていないため、各行のsizeof結果を配列に入れるトリックも機能しません。 一般的に、通常の配列よりも強力な何かを探す必要があります...

この問題の解決策は、構造を使用して配列をエミュレートすることです。 すべての行の長さを個別の構造に追加し、Loki :: TypeListを使用してバインドします。

 struct str_1 { static const int size = sizeof(str1); }; struct str_2 { static const int size = sizeof(str2); }; struct str_3 { static const int size = sizeof(str3); }; struct str_4 { static const int size = sizeof(str4); }; typedef LOKI_TYPELIST_4(str_1, str_2, str_3, str_4) List;
      
      





これで、このタイプのリストをバイパスして、それぞれのサイズを引き出すことができます。



最終C ++ 03
 struct str_1 { static const int size = sizeof(str1); }; struct str_2 { static const int size = sizeof(str2); }; struct str_3 { static const int size = sizeof(str3); }; struct str_4 { static const int size = sizeof(str4); }; typedef LOKI_TYPELIST_4(str_1, str_2, str_3, str_4) List; #define GetMaxLen(TypeList) \ \ template<class Cur_Type> \ struct len \ { \ static const int cur_size = Cur_Type::Head::size; \ static const int next_size = len<Cur_Type::Tail>::max_size; \ static const int max_size = cur_size > next_size ? cur_size : next_size ; \ }; \ \ template<> \ struct len<NullType> \ { \ static const int max_size = 0; \ }; \ \ static const int ml = len<TypeList>::max_size; \ GetMaxLen(List); //  *.cpp // LOKI_STATIC_CHECK((ml == sizeof(str3)), size_is_wrong);
      
      







このような構造は比較的少ない行数で維持しやすいため、このオプションは最も便利ではありません。 ただし、この量が増えると、行に適切な構造を追加するのを忘れてしまう可能性があります。

C ++ 11標準では、すべてがより美しく、便利になりました。 さらに、構造とタイプリストを「変形」する必要はありません。 ポインターを逆参照することはできますが、constexprおよびconstexpr関数内でのみ可能です。



最終C ++ 11
 constexpr const char str1[] = "Anna"; constexpr const char str2[] = "Denis"; constexpr const char str3[] = "Vladimir"; constexpr const char str4[] = "Alexey"; constexpr const char *arr[] = { str1, str2, str3, str4 }; #define GetMaxLenght(array) \ constexpr unsigned char str_len(const char* const str) \ {\ return *str ? (1 + str_len(str + 1)) : 0;\ }\ \ template <int index> \ struct MaxLenght\ {\ static const int prev_size = MaxLenght<index-1>::max_size;\ static const int cur_size = str_len(array[index]);\ static const int max_size = cur_size > prev_size ? cur_size : prev_size;\ };\ \ template <>\ struct MaxLenght<-1>\ {\ static const int max_size = 0;\ };\ static const int AmountStr = sizeof(array) / sizeof(array[0]);\ static const int array##_max_size = MaxLenght<AmountStr-1>::max_size; GetMaxLenght(arr); //  *.cpp // static_assert((arr_max_size == 8), "Error");
      
      









PSこの記事が誰かの役に立つことを願っています。

PPSブーストやその他のツールを使用してソリューションを提供してくれる人がいれば嬉しいです。



All Articles