LoginSignup
3
7

More than 5 years have passed since last update.

メンバの存在を判定する

Posted at

Swift について、そしてそれをいくつかの言語と比較する興味深い記事が投稿されているのを読みました。

Swiftの強力な機能であるstaticメソッド制約の紹介と、Kotlin, TypeScript, Java, Scala, C++との比較

比較対象になっている言語の内で私がよく知っているのは C++ だけなので他の記述は流し読みではあるのですが、ある型の性質を強制する仕組みとして C++ では「コンセプト」という概念がかなり前から検討されています。 (テンプレートが受け入れ可能な型の性質を記述する形で使い、ある型が特定のインターフェイスを満たしていることを表現するものではないという点でプロトコルとは異なるようです。) それがなかなか決定に至らないので、まわりくどい様々なやり方で制約を表現する方法が生み出されてきました。 今回は、あるクラスが特定の名前と型をもつメンバを持っているかどうかを判定する方法を紹介します。

元記事の IsLoadable を置き換える形で説明します。 元記事の C++ 版はあるクラスが loadable であるということの表現をふたつに分離しています。

  • loadable の要件を満たす (クラスがメンバ関数 load を持つ)
  • loadable であると定義する (IsLoadable<T>::value が真値である)

のふたつです。

この機能を使うプロジェクトできちんと規約を守ることができるならばよいのですが、可能であれば

  • loadable の要件を満たすならば loadable である

という形に一本化したいわけです。

それを満たすトレイト is_loadable は以下のように定義できます。

template<class T>
class is_loadable {
  template<class U, U (*)(Iterator<std::string>&)>
  struct helper_t { typedef T type; };

  template<class U, class V = T>
  struct helper : std::false_type {};

  template<class U>
  struct helper<U, typename helper_t<U, &U::load>::type> : std::true_type {};

public:
  static const bool value = helper<T>::value;
};

クラス Tload を持ち、なおかつその型が T (*)(Iterator<std::string>&) であれば is_loadable<T>::value は真です。

クラス Employee が loadable であることを陽に表したいのであれば、Employee を定義した後に以下の記述を入れておけばよいでしょう。

static_assert(is_loadable<Employee>::value, "Employee is not loadable");

あるいはマクロにしてしまった方がいいかもしれません。

#define declare_loadable(t) \
  static_assert(is_loadable<t>::value, #t " is not loadable")

declare_loadable(Employee);

以上は応用範囲の広い手法なので、活用すればできることは多いと思います。

3
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
7