テンプレートのデフォルト引数とか整数値の指定とか / C++11のconstexprのメモ


テンプレートのデフォルト引数とか整数値の指定とか

テンプレートには整数値を指定可能(signed or unsigend な int とか long とか)。浮動小数点とかクラスは無理。

template<class T = int, T number = 100>
struct Hoge {
 public:
  static const T Number = number;

  static T getNumber()
  {
    return number;
  }
};

void main()
{
  printf("%d  \n", Hoge<>::Number); // 100
  printf("%ld \n", Hoge<long, LONG_MAX>().getNumber()); // 9223372036854775807
}

constexpr

constexprを指定した関数はコンパイル時に実行することができる(ただし色々と制限がある)。

以下のソースコードは N進数の正の整数値を文字列に変換した時に何文字になるか計算したくて書いてみたもの。テンプレートとかconstexprとかいまいちわからないからテキトーだけど。。

/*!
 @abstract 整数値の階乗を行う
 @templatefield size4以上の整数値型を指定
 @param number 階乗される数値
 @param power 階乗の回数
 @param temp_ (コンパイル時に利用)
 */
template<typename Integer> constexpr Integer F8Pow(Integer number,
                                                   unsigned int power,
                                                   Integer temp_ = 1)
{
  typedef Integer T; // short hand
  static_assert(sizeof(T) >= 4, "int32_t以上のサイズに限定しとく");
  static_assert(std::is_integral<T>::value, "整数値のみ扱える");
  return power ? F8Pow(number, power - 1, temp_ * number) : temp_;
}

/*!
 @abstract 整数値型の最大値を取得
 @templatefield Integer 整数値型を指定
 */
template<typename Integer> constexpr Integer F8GetMaxInteger()
{
  static_assert(std::is_integral<Integer>::value, "整数値のみ扱える");
  return std::is_signed<Integer>::value
  ? (Integer)~((Integer)1 << (sizeof(Integer) * 8 - 1))
  : (Integer)-1;
}

/*!
 @abstract 整数値をradix進数の文字列で表現する為に必要なサイズを取得
 @templatefield Integer 整数値型を指定
 @templatefield radix 基数を指定
 @param target デフォルトはInteger型の最大値
 @param count_ (コンパイル時に利用)
 */
template<typename Integer, int radix>
constexpr Integer X8Radix_GetBufferSize(Integer target = F8GetMaxInteger<Integer>(),
                                        int count_ = 0)
{
  static_assert(2 <= radix && radix <= 64, "基数は2~64");
  return target
  ? X8Radix_GetBufferSize<Integer, radix>(target / radix, count_ + 1)
  : count_;
}

//
// 以下テストコード
//
void getBufferSizeTest()
{
  // 基数 64, 32, 16, 2
  static_assert(X8Radix_GetBufferSize<uint64_t, 64>() == 11, "");
  static_assert(X8Radix_GetBufferSize<uint32_t, 64>() == 6, "");
  static_assert(X8Radix_GetBufferSize<uint16_t, 64>() == 3, "");
  static_assert(X8Radix_GetBufferSize<uint8_t,  64>() == 2, "");

  static_assert(X8Radix_GetBufferSize<uint64_t, 32>() == 13, "");
  static_assert(X8Radix_GetBufferSize<uint32_t, 32>() == 7, "");
  static_assert(X8Radix_GetBufferSize<uint16_t, 32>() == 4, "");
  static_assert(X8Radix_GetBufferSize<uint8_t,  32>() == 2, "");

  static_assert(X8Radix_GetBufferSize<uint64_t, 16>() == 16, "");
  static_assert(X8Radix_GetBufferSize<uint32_t, 16>() == 8, "");
  static_assert(X8Radix_GetBufferSize<uint16_t, 16>() == 4, "");
  static_assert(X8Radix_GetBufferSize<uint8_t,  16>() == 2, "");

  static_assert(X8Radix_GetBufferSize<uint64_t, 8>() == 22, "");
  static_assert(X8Radix_GetBufferSize<uint32_t, 8>() == 11, "");
  static_assert(X8Radix_GetBufferSize<uint16_t, 8>() == 6, "");
  static_assert(X8Radix_GetBufferSize<uint8_t,  8>() == 3, "");

  static_assert(X8Radix_GetBufferSize<uint64_t, 4>() == 32, "");
  static_assert(X8Radix_GetBufferSize<uint32_t, 4>() == 16, "");
  static_assert(X8Radix_GetBufferSize<uint16_t, 4>() == 8, "");
  static_assert(X8Radix_GetBufferSize<uint8_t,  4>() == 4, "");

  static_assert(X8Radix_GetBufferSize<uint64_t, 2>() == 64, "");
  static_assert(X8Radix_GetBufferSize<uint32_t, 2>() == 32, "");
  static_assert(X8Radix_GetBufferSize<uint16_t, 2>() == 16, "");
  static_assert(X8Radix_GetBufferSize<uint8_t,  2>() == 8, "");

  // 基数 10
  static_assert(X8Radix_GetBufferSize<uint64_t, 10>() == 20, "");
  static_assert(X8Radix_GetBufferSize<uint32_t, 10>() == 10, "");
  static_assert(X8Radix_GetBufferSize<uint16_t, 10>() == 5, "");
  static_assert(X8Radix_GetBufferSize<uint8_t,  10>() == 3, "");

  static_assert(X8Radix_GetBufferSize<int64_t, 10>() == 19, "");
  static_assert(X8Radix_GetBufferSize<int32_t, 10>() == 10, "");
  static_assert(X8Radix_GetBufferSize<int16_t, 10>() == 5, "");
  static_assert(X8Radix_GetBufferSize<int8_t,  10>() == 3, "");
}

void getMaxIntegerTest()
{
  static_assert(F8GetMaxInteger<char>() == CHAR_MAX, "");
  static_assert(F8GetMaxInteger<short>() == SHRT_MAX, "");
  static_assert(F8GetMaxInteger<int>() == INT_MAX, "");
  static_assert(F8GetMaxInteger<long>() == LONG_MAX, "");
  static_assert(F8GetMaxInteger<long long>() == LLONG_MAX, "");

  static_assert(F8GetMaxInteger<unsigned char>() == UCHAR_MAX, "");
  static_assert(F8GetMaxInteger<unsigned short>() == USHRT_MAX, "");
  static_assert(F8GetMaxInteger<unsigned int>() == UINT_MAX, "");
  static_assert(F8GetMaxInteger<unsigned long>() == ULONG_MAX, "");
  static_assert(F8GetMaxInteger<unsigned long long>() == ULLONG_MAX, "");

  static_assert(F8GetMaxInteger<int8_t>() == INT8_MAX, "");
  static_assert(F8GetMaxInteger<int16_t>() == INT16_MAX, "");
  static_assert(F8GetMaxInteger<int32_t>() == INT32_MAX, "");
  static_assert(F8GetMaxInteger<int64_t>() == INT64_MAX, "");

  static_assert(F8GetMaxInteger<uint8_t>() == UINT8_MAX, "");
  static_assert(F8GetMaxInteger<uint16_t>() == UINT16_MAX, "");
  static_assert(F8GetMaxInteger<uint32_t>() == UINT32_MAX, "");
  static_assert(F8GetMaxInteger<uint64_t>() == UINT64_MAX, "");
}

void powTest()
{
  // Pow Tests
  static_assert(F8Pow(0, 0) == 1, "0の0乗は1とする");
  for (uint64_t i = 0; i <= 500; i++)
  {
    for (unsigned int power = 0; power <= 5; power++)
    {
      assert(F8Pow(i, power) == uint64_t(pow(i, power)));
    }
  }
}

void main()
{
  getBufferSizeTest();
  getMaxIntegerTest();
  powTest();
}
  1. コメントはまだありません。

  1. トラックバックはまだありません。

*


Advertisement