C++TT Chapter5 - SFINAE

考察・まとめ

問題

  1. SFINAEは何の略か。
  2. SFINAEとはどのような仕組みのことを言うか。
  3. 型特性を英語で言え。
  4. 型特性メタ関数とは何か。
  5. 型Tがiterator型を持っているか判定するhas_iteratorを様々な方法で実装せよ。

解答

  1. Substitution Failure Is Not An Error
  2. テンプレートをインスタンス化する際に置き換えに失敗したら、コンパイルエラーとせずに、その関数をオーバーロードの対象から外す仕組み。
  3. type traits
  4. 型特性メタ関数とは、型の特徴(整数型、ポインタ型、参照型、クラス、継承関係など)を判定したり型の特徴を操作したりするためのメタ関数。
#include <bits/stdc++.h>

// 1. sizeofを使う(C++03)
template<class T>
class has_iterator {
  typedef char yes;
  typedef struct { char a[2]; } no;

  template <class U> static yes test(typename U::iterator*);
  template <class U> static no  test(...);

public:
  static const/*expr*/ bool value = sizeof(test<T>(0)) == sizeof(yes);
};

// 2. constexprの関数
template <class T>
constexpr bool has_iterator_constexpr_func_impl(typename T::iterator*)
{
  return true;
}

template <class T>
constexpr bool has_iterator_constexpr_func_impl(...)
{
  return false;
}

template <class T>
constexpr bool has_iterator_constexpr_func()
{
  return has_iterator_constexpr_func_impl<T>(nullptr);
}

// 3. constexprのメタ関数
template <class T>
class has_iterator_constexpr {
  template <class U> static constexpr bool check(typename U::iterator*) { return true; }
  template <class U> static constexpr bool check(...) { return false; }

public:
  static constexpr bool value = check<T>(nullptr);
};

// 4. decltypeを使用したメタ関数
struct has_iterator_impl_decltype {
  template <class T> static std::true_type  check(typename T::iterator*);
  template <class T> static std::false_type check(...);
};

template <class T>
class has_iterator_decltype
  : public decltype(has_iterator_impl_decltype::check<T>(nullptr)) {};

int main() {

  static_assert(has_iterator<std::vector<int>>::value, "vector has iterator");
  static_assert(!has_iterator<int>::value, "int doesn't have iterator");

  static_assert(has_iterator_constexpr_func<std::vector<int>>(), "vector has iterator");
  static_assert(!has_iterator_constexpr_func<int>(), "int doesn't have iterator");

  static_assert(has_iterator_constexpr<std::vector<int>>::value, "vector has iterator");
  static_assert(!has_iterator_constexpr<int>::value, "int doesn't have iterator");

  static_assert(has_iterator_decltype<std::vector<int>>::value, "vector has iterator");
  static_assert(!has_iterator_decltype<int>::value, "int doesn't have iterator");

  return 0;
}