OSDN Git Service

[Update] FlagGroupのコンストラクタのconstexpr化
authorHabu <habu1010+github@gmail.com>
Fri, 2 Jun 2023 10:56:40 +0000 (19:56 +0900)
committerHabu <habu1010+github@gmail.com>
Fri, 2 Jun 2023 11:42:19 +0000 (20:42 +0900)
FlagGroupクラスで保持するフラグ列挙値の最大値がunsigned long long型の
ビットサイズ未満の場合、std::bitsetのunsigned long long型を引数に受け取
るconstexprコンストラクタを使用することでFlagGroupのコンストラクタも
constexprにする。

src/util/flag-group.h

index 4c79729..e476f64 100644 (file)
@@ -62,6 +62,16 @@ void write_bitset(const std::bitset<BITSET_SIZE> &bs, Func wr_byte_func, size_t
     }
 }
 
+template <typename InputIter>
+constexpr unsigned long long calc_bitset_val(InputIter first, InputIter last) noexcept
+{
+    auto result = 0ULL;
+    for (; first != last; ++first) {
+        result |= 1ULL << static_cast<int>(*first);
+    }
+    return result;
+}
+
 }
 
 /**
@@ -94,7 +104,7 @@ public:
      *
      * すべてのフラグがOFFの状態のFlagGroupクラスのインスタンスを生成する
      */
-    FlagGroup() = default;
+    constexpr FlagGroup() = default;
 
     /**
      * @brief FlagGroupクラスのコンストラクタ
@@ -104,7 +114,7 @@ public:
      *
      * @param il ONの状態で生成するフラグを指定した initializer_list
      */
-    FlagGroup(std::initializer_list<FlagType> il)
+    constexpr FlagGroup(std::initializer_list<FlagType> il)
         : FlagGroup(il.begin(), il.end())
     {
     }
@@ -117,7 +127,7 @@ public:
      *
      * @param range 範囲を示すEnumRangeクラスのオブジェクト
      */
-    FlagGroup(const EnumRange<FlagType> &range)
+    constexpr FlagGroup(const EnumRange<FlagType> &range)
         : FlagGroup(range.begin(), range.end())
     {
     }
@@ -128,11 +138,42 @@ public:
      * 入力イテレータで指定した範囲のリストに含まれるフラグがON、
      * それ以外のフラグがOFFの状態のFlagGroupクラスのインスタンスを生成する
      *
+     * FLAG_TYPE_MAXがunsigned long longのビットサイズ以下の場合、
+     * unsigned long longの値を引数に取るstd::bitsetのconstexpr化された
+     * コンストラクタが使用できるので、FlagGroupクラスでも
+     * constexprコンストラクタとしてこちらを選択する。
+     *
+     * @tparam InputIter 入力イテレータの型
+     * @param first 範囲の開始位置を示す入力イテレータ
+     * @param last 範囲の終了位置を示す入力イテレータ
+     */
+    template <flag_group::FlagIter<FlagType> InputIter>
+        requires(FLAG_TYPE_MAX <= sizeof(unsigned long long) * 8)
+    constexpr FlagGroup(InputIter first, InputIter last)
+        : bs_(flag_group::detail::calc_bitset_val(first, last))
+    {
+    }
+
+    /**
+     * @brief FlagGroupクラスのコンストラクタ
+     *
+     * 入力イテレータで指定した範囲のリストに含まれるフラグがON、
+     * それ以外のフラグがOFFの状態のFlagGroupクラスのインスタンスを生成する
+     *
+     * FLAG_TYPE_MAXがunsigned long longのビットサイズより大きい場合、
+     * C++20の範囲ではstd::bitsetをconstexprコンストラクタで初期化することは
+     * できないため、constexprではない通常のコンストラクタとしてこちらを選択する。
+     *
+     * @todo C++23以降であればstd::bitsetの多くのメンバ関数がconstepxr化されているので
+     * FLAG_TYPE_MAXがunsigned long longのビットサイズより大きくてもconstexpr化が
+     * 可能になると思われる。
+     *
      * @tparam InputIter 入力イテレータの型
      * @param first 範囲の開始位置を示す入力イテレータ
      * @param last 範囲の終了位置を示す入力イテレータ
      */
     template <flag_group::FlagIter<FlagType> InputIter>
+        requires(FLAG_TYPE_MAX > sizeof(unsigned long long) * 8)
     FlagGroup(InputIter first, InputIter last)
     {
         for (; first != last; ++first) {