第336章 std::enable_if_t を使って便利にする

std::enable_if_t ( C++14 ) は std::enable_if を型にしたクラステンプレートです。

std::enable_if_t のリファレンス実装は以下のようになります。

template< bool B, class T = void >
using enable_if_t = typename enable_if<B,T>::type;

メタ関数を使えるのは bool 型の B の箇所ですね。

もちろん T はデフォルトが void となってるので、戻り値型が無いのであれば設定は不要となります。

では簡単な実装例を見てみましょう。

注記

マクロについては クロスコンパイルのための組み込みマクロ を参照くださいね。

main.cpp. 

  1 #if __cplusplus < 201703L
  2 #  pragma message "-std=c++17をコマンドオプションに指定してください"
  3 #endif
  4
  5 #if defined(__GNUC__) && (__GNUC__ < 7)
  6 #  ifndef __clang__
  7 #    pragma message "GCCのバージョンが古いです"
  8 #  endif
  9 #elif defined(__clang__) && (__clang_major__  < 6)
 10 #  pragma message "Clangのバージョンが古いです"
 11 #endif
 12
 13 #include <type_traits>
 14 #include <iostream>
 15
 16 template<typename T, typename U>
 17 struct is_same : std::false_type{};
 18
 19 template<typename T>
 20 struct is_same<T,T> : std::true_type {};
 21
 22 template<typename T, typename ... U>
 23 std::enable_if_t<std::conjunction_v<is_same<T,U>...>>
 24 func_conjunction(T, U...)
 25 {
 26   std::cout << "conjunction: all params are of same type" << '\n';
 27 }
 28
 29 template<typename T, typename ... U>
 30 std::enable_if_t<std::disjunction_v<is_same<T,U>...>>
 31 func_disjunction(T, U...)
 32 {
 33   std::cout << "disjunction: all params are not of same type" << '\n';
 34 }
 35
 36 int main()
 37 {
 38   func_conjunction(1,2,3,4);
 39   func_disjunction(1,2,3,"abc");
 40 }

ビルドと実行結果. 

$ g++ main.cpp -std=c++17
$ ./a.out
conjunction: all params are of same type
disjunction: all params are not of same type

このサンプルコードは std::enable_if_t の第一引数である bool 値を評価するために std::conjunction_v と std::disjunction_v を使っています。

 22 template<typename T, typename ... U>
 23 std::enable_if_t<std::conjunction_v<is_same<T,U>...>>
 24 func_conjunction(T, U...)
 25 {
 26   std::cout << "conjunction: all params are of same type" << '\n';
 27 }

func_conjunction 関数は T 型と U をアンパックした型の全てが同一ならば標準出力をします。

また戻り値型は std::enable_if_t のデフォルト型である void 型となります。

もう一つの関数 func_disjunction 関数は T 型とアンパックした型のうち一つでも同一ならば、標準出力をします。

 29 template<typename T, typename ... U>
 30 std::enable_if_t<std::disjunction_v<is_same<T,U>...>>
 31 func_disjunction(T, U...)
 32 {
 33   std::cout << "disjunction: all params are not of same type" << '\n';
 34 }

disjunction か conjunction のどちらを std::enable_if_t と合わせて使うかは用途にもよりますが過去には自作で似たようなメタ関数を作っていた時代もあったことを考えれば便利にはなったと言えないでもないですね。

Copyright 2017-2018, by Masaki Komatsu