とくにあぶなくないRiSKのブログ

危ないRiSKのブログだったかもしれない。本当はRiSKだけどググラビリティとか取得できるIDの都合でsscriskも使ったり。

strong typedef 作ってみた

型安全性を重視して,異なる型との演算ができず,型の昇格も起こらない strong typedef(strong_typedef) を作ってみた。
今のところ is_arithmetic が true になるような型で使うことを想定してる。
sscrisk::another::type がユーザーに開いたインターフェース。

使い方・サンプル

#include<cassert>
#include<sscrisk/another.hpp>

int main()
{
 using sscrisk::another;

 {
  // strong_typedef int my_int;
  typedef another<int>::type my_int;

  // name = {N} または name{N} で初期化
  my_int a = {42}, b{32};

  // 元の型ができることは大抵できる
  a++; a--; !a; ~a; ++a; --a; +a; -a;
  a * b; a / b; a % b; a + b; a - b; a << 1; a >> 1;
  a < b; a <= b; a > b; a >= b; a == b; a != b; a & b; a ^ b; a | b;
  a && b; a && false; true && b; a || b; a || true; false || b;
  a += b; a -= b; a *= b; a /= b; a %= b; a &= b; a ^= b; a |= b; a <<= 1; a >>= 1;

  // 組込みの演算
  my_int* p = &a; *p = b;
 }
 {
  // strong typedef bool bit;
  typedef another<bool>::type bit;

  // constexpr にできる
  constexpr bit off{false}, on{true};

  // 型安全
  // 型の昇格は起きない
  // 型の昇格とは {bool, signed char, unsigned char, char, short, unsigned short} が
  // {int, unsigned} へと型変換すること
  // constexpr int test = on & off; // NG: int = bit
  constexpr bit test = on & off;
  assert(test == off);
  assert((on | off) == on);
  assert((on ^ off) == on);
 }
 {
  // タグで完全に別の型を作れる
  typedef another<int, struct kg_tag>::type kg;
  typedef another<int, struct cm_tag>::type cm;

  kg weight{60};
  cm height{179};
  int test{100};

  // 型安全
  // 異なる型との演算はできない
  // test + weight;   // NG: int + kg
  // weight + height; // NG: kg + cm
  // test = weight;   // NG: int = kg
  // weight = test;   // NG: kg = int

  // 最低限の抜け穴。多用悪用厳禁
  height.base = test;   // base で元の型へアクセス
  test = weight.base;   // base で元の型へアクセス
  true || weight.base;  // base で短絡評価
  false && height.base; // base で短絡評価
 }
}

ライブラリのコード

strong typedef — Gist