Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Template Meta Programming入門から応用まで

9,777 views

Published on

  • Be the first to comment

Template Meta Programming入門から応用まで

  1. 1. Template Meta Programming 入門から応用まで @fimbul11 2013/09/28 C++勉強会 @ tkb #2
  2. 2. 自己紹介 twitter : @fimbul11 github : fimbul University of Tsukuba B3  専攻 : 情報とメディア技術(mast) プログラミングとかやってます、歴は2年ちょっとぐらいです C++とかやってます、歴は1年半ぐらいです ペン回しとか出来ます、歴は7年ぐらいです
  3. 3. はじめに このような無名の勉強会に遠方からも多く の人に来ていただけました、本当にありが とうございます
  4. 4. おしながき 1. Templateの基本確認 2. Template Meta Programmingとは 3. Template Meta Programming入門 4. Template Meta Programming応用 5. その他付録 6. まとめ 7. 質疑応答
  5. 5. おしながき 1. Templateの基本確認 2. Template Meta Programmingとは 3. Template Meta Programming入門 4. Template Meta Programming応用 5. その他付録 6. まとめ 7. 質疑応答
  6. 6. Templateの基本確認 今日は ・C++未経験者 ・C++初心者 ・C++初心者(意味深) ・C++中級者及び上級者 ・歩くC++規格レベル ・人間C++コンパイラ など色々な方が居る可能性があるので
  7. 7. Templateの基本確認 今日は ・C++未経験者 ・C++初心者 ・C++初心者(意味深) ・C++中級者及び上級者 ・歩くC++規格レベル ・人間C++コンパイラ など色々な方が居る可能性があるので
  8. 8. Templateの基本確認 今日は ・C++未経験者 ・C++初心者 ・C++初心者(意味深) ・C++中級者及び上級者 ・歩くC++規格レベル ・人間C++コンパイラ など色々な方が居る可能性があるので
  9. 9. Templateの基本確認 今日は ・C++未経験者 ・C++初心者 ・C++初心者(意味深) ・C++中級者及び上級者 ・歩くC++規格レベル ・人間C++コンパイラ など色々な方が居る可能性があるので
  10. 10. Templateの基本確認 今日は ・C++未経験者 ・C++初心者 ・C++初心者(意味深) ・C++中級者及び上級者 ・歩くC++規格レベル ・人間C++コンパイラ など色々な方が居る可能性があるので
  11. 11. Templateの基本確認 今日は ・C++未経験者 ・C++初心者 ・C++初心者(意味深) ・C++中級者及び上級者 ・歩くC++規格レベル ・人間C++コンパイラ など色々な方が居る可能性があるので
  12. 12. Templateの基本確認 今日は ・C++未経験者 ・C++初心者 ・C++初心者(意味深) ・C++中級者及び上級者 ・歩くC++規格レベル ・人間C++コンパイラ など色々な方が居る可能性があるので
  13. 13. Templateの基本確認 ガチ勢の方はお手柔らかにお願いします
  14. 14. Templateの基本確認 初心者は知らないことがあるかも そうでない人も少しおさらいをしておく という意味で
  15. 15. Templateの基本確認 規格に基づいて文法などの Templateの基本を確認する  
  16. 16. Templateの基本確認 規格に基づいて文法などの Templateの基本を確認する むしろややこしいTemplateのルールについて 把握する事こそがTemplate Meta Programming 最大の山場といえます
  17. 17. Templateの基本確認 規格に基づいて文法などの Templateの基本を確認する 非常に重要な部分であり、templateを使った 経験が少ないとこれだけで十分すぎるぐら いつらいと思います
  18. 18. Templateの基本確認 ・C++11規格に沿う ・ただし細かい部分には触れない  (各自で規格を確認してほしい   自分もまる覚えはしていない) ・C++14~の機能(Variable Templates等)  はその他付録の章で扱う
  19. 19. Templateの基本確認 結構量があるので既に知ってる人は適当に 聞き流しつつ他の作業でもしていて下さい
  20. 20. Templateの基本確認 目次 1. Template is 何 2. テンプレートの文法 2-1. テンプレートパラメータ 2-2. クラステンプレート 2-3. 関数テンプレート 2-4. エイリアステンプレート 2-5. 可変長引数テンプレート 2-6. template template parameter
  21. 21. Templateの基本確認 目次 1. Template is 何 2. テンプレートの文法 2-1. テンプレートパラメータ 2-2. クラステンプレート 2-3. 関数テンプレート 2-4. エイリアステンプレート 2-5. 可変長引数テンプレート 2-6. template template parameter
  22. 22. Template is 何 テンプレートって何ですか?
  23. 23. Template is 何 テンプレートって何ですか? N3337見ましょう
  24. 24. Template is 何 14 Templates A template defines a family of classes or functions or an alias for a family of types.
  25. 25. Template is 何 テンプレートは クラスや関数、型エイリアスのファミリー を定義する
  26. 26. Template is 何 確認するまでもなかったかもしれません 次に文法を確認していくことにします
  27. 27. Templateの基本確認 目次 1. Template is 何 2. テンプレートの文法 2-1. テンプレートパラメータ 2-2. クラステンプレート 2-3. 関数テンプレート 2-4. エイリアステンプレート 2-5. 可変長引数テンプレート 2-6. template template parameter
  28. 28. テンプレートの文法 テンプレートの文法を確認する  
  29. 29. テンプレートの文法 テンプレートの文法を確認する 規格を参照して定義から見ていく
  30. 30. テンプレートの文法 テンプレートの文法を確認する template-declaration: template < template-parameter-list > declaration template-parameter-list: template-parameter template-parameter-list , template-parameter
  31. 31. テンプレートの文法 テンプレートの文法を確認する template-declaration: template < template-parameter-list > declaration template-parameter-list: template-parameter template-parameter-list , template-parameter
  32. 32. テンプレートの文法 テンプレートは template < template-parameter-list > declaration   として定義される
  33. 33. テンプレートの文法 テンプレートは template < template-parameter-list > declaration   として定義される
  34. 34. テンプレートの文法 template-parameter-listは template-parameter 又は template-parameter-list , template-parameter  として定義される
  35. 35. テンプレートの文法 template-parameter-listは template-parameter 又は template-parameter-list , template-parameter  として定義される
  36. 36. Templateの基本確認 目次 1. Template is 何 2. テンプレートの文法 2-1. テンプレートパラメータ 2-2. クラステンプレート 2-3. 関数テンプレート 2-4. エイリアステンプレート 2-5. 可変長引数テンプレート 2-6. template template parameter
  37. 37. Template parameters The syntax for template-parameters is: template-parameter: type-parameter parameter-declaration type-parameter: class ...opt identifieropt class identifieropt= type-id typename ...opt identifieropt typename identifieropt= type-id template < template-parameter-list > class ...opt identifieropt template < template-parameter-list > class identifieropt= idexpression optの後の要素は省略可能
  38. 38. Template parameters The syntax for template-parameters is: template-parameter: type-parameter parameter-declaration type-parameter: class ...opt identifieropt class identifieropt= type-id typename ...opt identifieropt typename identifieropt= type-id template < template-parameter-list > class ...opt identifieropt template < template-parameter-list > class identifieropt= idexpression optの後の要素は省略可能
  39. 39. Template parameters template-parameterは type-parameter又は parameter-declaration  である
  40. 40. Template parameters template-parameterは type-parameter又は parameter-declaration  である
  41. 41. type-parameter まずtype-parameterの定義の一部のみ紹介する type-parameter : class ...opt identifieropt class identifieropt= type-id typename ...opt identifieropt typename identifieropt= type-id が付いた要素は省略可能 opt 一見種類が多い
  42. 42. type-parameter まずtype-parameterの定義の一部のみ紹介する type-parameter : class ...opt identifieropt class identifieropt= type-id typename ...opt identifieropt typename identifieropt= type-id 対応する色のもの同士は実質同じ また = type-idの部分はデフォルト引数の有無
  43. 43. type-parameter 定義の数は一見多いが実際は結構単純 順番に定義の意味を見ていく
  44. 44. type-parameter この4つにおいてtype-parameterの頭の部分では classキーワードとtypenameキーワード は同じ意味 (他の場所では当然意味が違うので注意する、 C++には文脈によって同じキーワードに複数 の意味を持たせる文化がある) (例えばtemplate template parameterの場合違う)
  45. 45. type-parameter 最も単純なtype-parameterを使ったtemplate例 template<class> (又はtemplate<typename>) type-parameterのclassとtypenameキーワードは 今後の説明ではclassで統一する (スライドの都合上、短い方がありがたい)
  46. 46. type-parameter type-parameter : class ...opt identifieropt identifierはtype-parameterの名前 例 template<class Type>
  47. 47. type-parameter type-parameter : class ...opt identifieropt = type-id type-idがデフォルト引数になる 例 template<class Type = int> 何も渡されなければTypeはintになる
  48. 48. type-parameter 関数のデフォルト引数同様に 最初のデフォルト引数を持つパラメータ以降 の全パラメータにデフォルト引数が必要 例 template<class T1 = int, class T2 = int> class A;
  49. 49. type-parameter デフォルト引数の設定は複数に分けて書いて も統合される(N3337 305p) template<class T1, class T2 = int> class A; template<class T1 = int, class T2> class A;   は以下に等しい template<class T1 = int, class T2 = int> class A;
  50. 50. type-parameter 当然後ろの要素から順に設定する必要がある template<class T1 = int, class T2> class A; template<class T1, class T2 = int> class A; この順だと1行目でダメです error: no default argument for ‘T2’
  51. 51. type-parameter 例まとめ template<class> 無名 template<class = int> デフォルト引数有り template<class Type> 名前有り template<class Type = int> デフォルト引数有り template<class T1, class T2> 複数のパラメータ
  52. 52. type-parameter 別の定義は後の章で見るので ひとまずtype-parameterをこれで終わります
  53. 53. Template parameters template-parameterは type-parameter又は parameter-declaration  である
  54. 54. parameter-declaration parameter-declaration: attribute-specifier-seqopt decl-specifier-seq declarator attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause attribute-specifier-seqopt decl-specifier-seq abstractdeclaratoropt attribute-specifier-seqopt decl-specifier-seq abstractdeclaratoropt= initializer-clause
  55. 55. parameter-declaration parameter-declarationは non-type template-parameter  (非型テンプレートパラメータ)の場合に使う
  56. 56. non-type template-parameter 例を見た方が早い template<char C> template<int N> 渡される引数がnon-typeなtemplate-parameter int Nやchar Cがparameter-declarationにあたる
  57. 57. non-type template-parameter もっと具体的な例 template<  class T, // Tはまだ何型か分からない std::size_t N // Nはstd::size_t型のパラメータ > struct array; std::array<int, 10>の要素数10を受け取っている Nがnon-type template-parameter
  58. 58. non-type template-parameter 全ての型が non-type template-parameterに なれるわけではない
  59. 59. non-type template-parameter non-type template-parameterになれる条件(重要) 1. integral or enumeration type(実質整数型) 2. pointer to object or pointer to function 3. lvalue reference to object or lvalue reference to function 4. pointer to member  5. std::nullptr_t (実質ポインタ型)  (又はこれらにcv修飾子が付いたもの) のいずれかを満たす型であるとき
  60. 60. non-type template-parameter non-type template-parameterになれる条件は 要するに整数型かポインタ型か左辺値参照
  61. 61. non-type template-parameter 例 template<std::size_t N> std::size_tは整数型のtypedefなのでwell-formed class myClass {}; template<myClass Arg> 先程の条件を満たさないクラス等はill-formed
  62. 62. non-type template-parameter 例 N3337 p305 template<double d> class X; // Error 浮動小数点型は条件に一致しない template<double* pd> class Y; // OK pointer to objectなのでOK template<double& rd> class Z; // OK lvalue referenceなのでOK
  63. 63. non-type template-parameter 右辺値は値渡しで受け取る必要がある non-type template-parameterになれないrvalue referenceは論外だ し、const lvalue referenceでもダメ (どうせ渡せる型が小さいデータなのでコピーで然程問題ない) 例 template<int N> class X; using type = X<0>; // OK template<const int& N> class Y; using type = Y<0> // error: ‘0’ is not a valid template argument because it is not an lvalue
  64. 64. non-type template-parameter non-type template-parameterに渡せるものにも 条件がある
  65. 65. non-type template-parameter non-type template-parameterに渡せるもの ・定数式 ・関数のアドレス ・外部リンケージのあるオブジェクト ・静的クラス・メンバのアドレス
  66. 66. non-type template-parameter non-type template-parameterに渡せるもの 定数式(分類に不安があるが…) ・非型テンプレート引数(先程のNなど) ・コンパイル時定数(constexpr)  (後で説明する) ・sizeofやsizeof...など
  67. 67. non-type template-parameter non-type template-parameterに渡せるもの 関数のアドレス ・説明不要、f()などのアドレス
  68. 68. non-type template-parameter non-type template-parameterに渡せるもの 外部リンケージのあるオブジェクト ・extern修飾されたもの
  69. 69. non-type template-parameter non-type template-parameterに渡せるもの 静的クラス・メンバのアドレス ・説明不要、そのままの意味
  70. 70. template-parameter template-parameterに関しては、他にも細かい 事が大量に規定されているので適宜規格を調 べる必要がある
  71. 71. template-parameter template-parameterまとめ ・テンプレートパラメータには型パラメータ  と非型パラメータがある ・非型パラメータになるものや渡せるものは  限られている
  72. 72. Templateの基本確認 目次 1. Template is 何 2. テンプレートの文法 2-1. テンプレートパラメータ 2-2. クラステンプレート 2-3. 関数テンプレート 2-4. エイリアステンプレート 2-5. 可変長引数テンプレート 2-6. template template parameter
  73. 73. Class templates A class template defines the layout and operations for an unbounded set of related types.
  74. 74. Class templates クラステンプレートは、関連する型(要する に扱う要素の型が違うだけのクラス群)のレ イアウトをまとめて定義する
  75. 75. Class templates 例 汎用的な配列クラス N3337 P315 template<class T> class Array {  T* v; // Tは引数として渡された型に置き換わる int sz;  public:  explicit Array(int);  T& operator[](int);  T& elem(int i) { return v[i]; }  };   Array<int>やArray<char>は渡した型を扱える
  76. 76. Class templates クラスメンバテンプレート class Test { public: template<class T> T f(T arg) { return arg; } // 関数テンプレートは後で取り上 げる };   クラスメンバもテンプレートに出来る operator等もテンプレート化可能
  77. 77. Class templates 非型テンプレートパラメータを使う例 template<std::size_t N> struct integer { // structも当然テンプレート化可能 static constexpr std::size_t value = N; };  Nの型にconst等は付いていなくても非型テ ンプレートパラメータは(暗黙に)コンパイル 時に値が決まる定数として扱える (constexpr修飾された値の初期化にも使える)
  78. 78. Class templates 非型テンプレートパラメータを使う例 template<std::size_t N> struct integer { static constexpr std::size_t value = ++N; };  当然、非型テンプレートパラメータの型の 書き換えはill-formedである (定数なのでうっかり試みても失敗する) error: increment of read-only location ‘N’
  79. 79. Class templates 違法な例を招く行為(当然してはいけない) template<class T, T v> struct data { static constexpr T* get_address() { return const_cast<T*>(&static_cast<const T&>(v)); } };  このような行為は万死に値する
  80. 80. Class templates 補足事項 Template specializations  テンプレートの特殊化
  81. 81. Class templates Template specializations テンプレートの特殊化 template<class T = int> struct A { static int x; }; template<class U> void g(U) { } template<> struct A<double> {}; // specialize for T == double template<> struct A<> { }; // specialize for T == int template<> void g(char) { } // specialize for U == char テンプレートクラスやテンプレート関数のtype-parameterに ある値が入った状態のものは特殊化されているといえる
  82. 82. Class templates class template partial specializations クラステンプレートの部分特殊化
  83. 83. Class templates 例 template<class T1, class T2, int I> class A {}; // unspecialized template<class T, int I> class A<T, T*, I> {}; template<class T1, class T2, int I> class A<T1*, T2, I> {}; template<class T> class A<int, T*, 5> {}; template<class T1, class T2, int I> class A<T1, T2*, I> {};
  84. 84. Class templates template<class T1, class T2, int I> class A {}; // unspecialized template<class T, int I> class A<T, T*, I> {}; このように抽象的なテンプレートパラメータの数を減らし 部分的に具体的要素に置き換えた特殊化を作る事が出来る
  85. 85. Class templates template<class T1, class T2, int I> class A {}; // unspecialized template<class T, int I> class A<T, T*, I> {}; 部分特殊化されたテンプレートは、条件を満たす場合には 特殊化されていないテンプレートより優先的にマッチする
  86. 86. Class templates template<class T1, class T2, int I> class A {}; // unspecialized template<class T, int I> class A<T, T*, I> {}; // classA<int, int*, 0>な どの場合だけこちらの定義が使われる ある条件を満たす場合のみ実装を切り替える事が出来る これはTemplate Meta Programmingにおいて非常に重要
  87. 87. Class templates また、部分特殊化によっては template<int N> struct A; template<> struct A<0>; のようにtemplateの中身が空<>になることも あるが特に文法上問題無い
  88. 88. Class templates 勿論、型テンプレートパラメータだけでな く非型テンプレートパラメータも部分特殊 化出来る(例は後の章で登場する)
  89. 89. Class templates テンプレートの特殊化及び部分特殊化が出 来るケースにも条件がある
  90. 90. Class templates テンプレートの特殊化が出来るケース 特殊化できる OK : 名前空間スコープ NG : クラススコープ つまりクラスのメンバは特殊化不可能
  91. 91. Class templates テンプレートの部分特殊化が出来るケース 部分特殊化できる: OK : クラステンプレート NG : 関数テンプレート 部分特殊化は非クラスメンバのクラステンプ レート限定の機能といえる
  92. 92. Class templates Class templatesまとめ ・クラステンプレートは、 関連する型のレ  イアウトをまとめて定義する ・名前空間スコープのクラステンプレートの  み部分特殊化によって実装を切り替え可
  93. 93. Templateの基本確認 目次 1. Template is 何 2. テンプレートの文法 2-1. テンプレートパラメータ 2-2. クラステンプレート 2-3. 関数テンプレート 2-4. エイリアステンプレート 2-5. 可変長引数テンプレート 2-6. template template parameter
  94. 94. Function templates A function template defines an unbounded set of related functions.
  95. 95. Function templates 関数テンプレートは、関連する関数(要する に扱う要素の型が違うだけの関数群)をまと めて定義する
  96. 96. Function templates 例 template<class T> T twice(T arg) { return arg * 2; } twice(2); // 4 twice(2.5); // 5.0 整数も浮動小数点も扱える
  97. 97. Function templates Template argument deduction テンプレート引数の型推論
  98. 98. Function templates 先程の例 twice(2); twice(2.5); twice<int>(2)と書かなくとも適切にint版の twiceが呼ばれ、twice<double>(2.5)と書かな くとも適切にdouble版のtwiceが呼ばれた
  99. 99. Function templates このような引数からテンプレートパラメー タ型を推論する機能が Template argument deduction
  100. 100. Function templates 幾つかの例外を除き、渡した型がそのまま 推論される
  101. 101. Function templates 例外1 ・配列型(T[N])はポインタ(T*)に変換される ・関数型(R(Args...))は関数ポインタ  (R(*(Args...))に変換される
  102. 102. Function templates 例外2 ・値渡しの場合のみトップレベルのcv修飾子  が無視される
  103. 103. Function templates 例外2 template<class T> T test(T arg) { return arg; } int a = 0; test(a); // Tはint型 const int b = 0; test(b); // Tはint型
  104. 104. Function templates 例外2 このような挙動の理由は、値コピーを取る場合、結局元の オブジェクトの値が変更される可能性が無いためとされる const int b = 0; test(b); // (testの中ではbのコピーが扱われるのでbの値自体 が変えられることはない、じゃあコピーするときはconst無 視してもいいんじゃね)…とコンパイラは思う
  105. 105. Function templates 例外2 constと同様にvolatileも無視される
  106. 106. Function templates 例外2 よって値を変更する可能性のある参照やポ インタ渡しの場合はcv修飾子も保持される template<class T> T test(T& arg) { return arg; } const int b = 0; test(b); // Tはint& const型
  107. 107. Function templates 例外2 ただし明示的に渡せば、渡した通りになる const int b = 0; test<const int>(b); // Tはconst intになる
  108. 108. Function templates 例外2 cv修飾子が無視される可能性があるのは トップレベルの型のみである 例えばvector<const int>などのconst int部分は トップレベルではないので無視されない
  109. 109. Function templates 当然非型テンプレートも推論してくれる template<class T, T N> constexpr T get(std::integral_constant<T, N>) { return N; } std::cout << get(std::integral_constant<int, 0>()) << std::endl; // T = int, N = 0と推論され、0が出力される
  110. 110. Function templates std::integral_constant<T, N> のようにテンプレートクラスのテンプレー トパラメータとしてネストされた内部の型 でもTやNとして推論出来る
  111. 111. Function templates Template argument deductionの規格を厳密に 読んで全てのルールを把握していくだけで尋 常じゃない大変さなので残りは省略します
  112. 112. Function templates Function template overloading 関数テンプレートのオーバーロード
  113. 113. Function templates 部分特殊化は出来ないが特殊化は出来る これらはオーバーロードされる template<class T> void output(T val); template<> void output(const std::string& val);
  114. 114. Function templates オーバーロードの解決に関しては省略する N3337 14.5.6.2 Partial ordering of function templates  を参照して欲しい ambiguousになる例など取り上げられている
  115. 115. Function templates Function templatesまとめ ・関数テンプレートは引数から型を推論し  てくれる ・特殊化、オーバーロードが可能である
  116. 116. Templateの基本確認 目次 1. Template is 何 2. テンプレートの文法 2-1. テンプレートパラメータ 2-2. クラステンプレート 2-3. 関数テンプレート 2-4. エイリアステンプレート 2-5. 可変長引数テンプレート 2-6. template template parameter
  117. 117. Alias templates 1. A template-declaration in which the declaration is an alias-declaration declares the identifier to be a alias template. An alias template is a name for a family of types. The name of the alias template is a template-name.
  118. 118. Alias templates 2. When a template-id refers to the specialization of an alias template, it is equivalent to the associated type obtained by substitution of its template-arguments for the templateparameters in the type-id of the alias template.
  119. 119. Alias templates もはや訳すのも面倒なので実例を見る
  120. 120. Alias templates template <class T> using add_pointer = typename std::add_pointer< T >::type; add_pointer<T>はstd::add_pointer< T >::typeと同じ型になる
  121. 121. Alias templates 別にtemplateである必要は無い using type = int;  typeはint型の別名として使える、簡単!
  122. 122. Alias templates typedef int integer; using integer = int; は同じ効果 typedefの代わりとして使える (ただし使えるのはC++11以降)
  123. 123. Alias templates Template Meta Programmingではtypenameと か::typeを書かなくて済むようにする為に 使ったりする template<class T> using add_p = typename std::add_pointer<T>::type; add_p<int>; // int*
  124. 124. Alias templates 余談 typedefは指定子である 指定子の順番に意味は無い typedef int Integer1; (こっちが多分メジャー) int typedef Integer2; (稀に見かける) // どちらもOK int Integer3 typedef;   // これはダメ
  125. 125. Alias templates typedef int Integer1; のように どうしてtypedef A B;の形がメジャーなのか?
  126. 126. Alias templates 次のような例を考える int typedef type; はOKだが int* typedef type; はダメ 「*」は、指定子(specifier)ではなく、宣言子 (declarator)のため
  127. 127. Alias templates 結論 多分、typedefを最初に書かない場合には宣 言子が出てきた時に面倒臭いから
  128. 128. Alias templates 後方互換性を気にしなくていいなら正直 typedefよりusingを使うと良いと思います (個人的にはusingの方が好き)
  129. 129. Alias templates 余談 template structなどの状態のメタ関数では遅延されるタイミ ングで正格評価される場合がある?(エイリアステンプレー トにしたところコンパイル時間が大幅に伸びた経験がある)
  130. 130. Alias templates Alias templatesまとめ ・usingを使う事で型の別名として使える ・typedefと違いテンプレート化出来る
  131. 131. Templateの基本確認 目次 1. Template is 何 2. テンプレートの文法 2-1. テンプレートパラメータ 2-2. クラステンプレート 2-3. 関数テンプレート 2-4. エイリアステンプレート 2-5. 可変長引数テンプレート 2-6. template template parameter
  132. 132. Variadic templates 1. A template parameter pack is a template parameter that accepts zero or more template arguments.
  133. 133. Variadic templates 2. A function parameter pack is a function parameter that accepts zero or more function arguments.
  134. 134. Variadic templates つまり、 ・可変長引数を取るクラス ・可変長引数を取る関数 の為の可変長引数テンプレート
  135. 135. Variadic templates The syntax for template-parameters is: template-parameter: type-parameter parameter-declaration type-parameter: class ...opt identifieropt class identifieropt= type-id typename ...opt identifieropt typename identifieropt= type-id template < template-parameter-list > class ...opt identifieropt template < template-parameter-list > class identifieropt= idexpression optの後の要素は省略可能
  136. 136. Variadic templates 先程Template parametersで飛ばした ...opt  を使う また、「...」を規格上ellipsisと呼ぶ 先の定義通りデフォルト引数は取れない
  137. 137. Variadic templates template<class... Types> struct Tuple {};  class...の部分は可変長引数テンプレート その名前はTypes
  138. 138. Variadic templates template<class... Types> struct Tuple {}; 可変長引数テンプレートは0個以上の引数を 好きなだけ受け取れる 勿論、非型テンプレート引数版も可能 template<int... Indices> struct Numbers {};
  139. 139. Variadic templates template<class... Types> struct Tuple {}; 例 Tuple<int, double, char, void*>  このように好きなだけ渡せる template<int... Indices> struct Numbers {}; Numbers<1,2,3,4,5>
  140. 140. Variadic templates このような可変長引数部分の事を template parameter pack  と呼ぶ
  141. 141. Variadic templates 例 template<class... Types> struct List; template<class Type, Type... Args> struct Data; TypesやArgsはTemplate Parameter Pack
  142. 142. Variadic templates 可変長引数テンプレートは基本的には、 template parameterのうち最後でなければな らない(一部例外がある) template<class Type, class... Types> // OK template<class... Types, class Type> // NG
  143. 143. Variadic templates 例外 template<std::size_t... Indices1, std::size_t... Indices2> void f(index_tuple<Indices1...>, index_tuple<Indices2...>); ・関数の引数の型が持つパラメータパック  を推論する場合 ・特に可変長引数を持つ型の引数を複数受  け取る場合には複数のパラメータパック  を持つことが出来る
  144. 144. Variadic templates pack expansion  受け取ったパラメータパックを展開する
  145. 145. Variadic templates 可変長引数として受け取ったテンプレート パラメータパックを使う為には それを展開する必要がある
  146. 146. Variadic templates 展開はpattern and an ellipsisからなる
  147. 147. Variadic templates template<class ResultType, class... Types> ResultType sum(const Types&... Args); sum<int>(1,2,3,4,5,6,7,8,9,10); 可変長の関数テンプレートにおいて型推論を行い、その結 果をTypesに格納して受け取っている
  148. 148. Variadic templates template<class Type, class... Types> Type sum(const Types&... Args); におけるconst Types&...がパック展開 class... Typesはsum<int>(1,2,3,4,5,6,7,8,9,10); なのでTypesはint, int, int, int, int, int, int, int, int, int に推論される
  149. 149. Variadic templates このときTypes...は int, int, int, int, int, int, int, int, int, int  に展開される
  150. 150. Variadic templates patternはパック展開時に処理を施す const Types&...はTypesの受け取った型1つ1つ にconst修飾及び参照&を付加した型になる よってconst Types&...は const int&, const int&, const int&, const int&, const int&, const int&, const int&, const int&, const int&, const int&  に展開される
  151. 151. Variadic templates 結果として template<class ResultType, class... Types> ResultType sum(const Types&... Args);は sum<int>(1,2,3,4,5,6,7,8,9,10);のとき int sum<int>(const int&, const int&, const int&, const int&, const int&, const int&, const int&, const int&, const int&, const int&); と等価になっている
  152. 152. Variadic templates 同様にして関数の引数もparameter packとし て受け取っている template<class ResultType, class... Types> ResultType sum(const Types&... Args);
  153. 153. Variadic templates sum<int>(1,2,3,4,5,6,7,8,9,10);のとき Args...は1,2,3,4,5,6,7,8,9,10になる
  154. 154. Variadic templates 例として受け取った数の総和を計算する関数を挙げる template<class Type, class... Types> Type sum(const Types&... Args) { // parameter pack Type result = 0; for(auto& elem : { static_cast<Type>(Args)... }) // pack expansion { result += elem; } return result; } int main() { std::cout << sum<int>(1,2,3,4,5,6,7,8,9,10) << std::endl; // 55 }
  155. 155. Variadic templates この例ではinitializer-listに対して { static_cast<Type>(Args)... } を展開することで {static_cast<Type>(1), static_cast<Type>(2), static_cast<Type>(3),  中略, static_cast<Type>(10)} を生成している 結果として今回は全要素がint型の{1,2,3,4,5,6,7,8,9,10}になる
  156. 156. Variadic templates sum<int>(1,2.0,3.5,4,5,6,7,8,9,10); のように型が異なる要素が混入していてもキャストしながら 展開する事が出来る
  157. 157. Variadic templates 補足 template parameter packの要素数を得るには sizeof...を使う sizeof...(Types) sizeof...(Args) sizeof...に対してはパックは展開せずに渡す sizeof...(Types...) // NG
  158. 158. Variadic templates 余談 ピリオドが6つ連続するコードが存在し得る (多分Sprout等で稀にお目にかかれる) 例 template<class... T> void f(T......); // なにこれキモイ
  159. 159. Variadic templates これは前半3つのピリオドがVariadic Templatesの展開、後半3つ のピリオドがC言語スタイルの可変長引数の...であり、真ん中 のカンマが省略されたもの template<class... T> void f(T..., ...); // ただのellipsis, ellipsisにすぎない に等しいのでビビる必要は無い
  160. 160. Variadic templates Variadic templatesまとめ ・Variadic TemplatesはTemplate Parameter Packと  して受け取る ・型パラメータ、非型パラメータを扱える ・型パラメータは関数の引数の型として利用出来る ・非型パラメータは関数の引数として利用出来る ・Template Parameter Packはpattern and ellipsis  によって展開してから使う
  161. 161. Templateの基本確認 目次 1. Template is 何 2. テンプレートの文法 2-1. テンプレートパラメータ 2-2. クラステンプレート 2-3. 関数テンプレート 2-4. エイリアステンプレート 2-5. 可変長引数テンプレート 2-6. template template parameter
  162. 162. Template Template Parameters The syntax for template-parameters is: template-parameter: type-parameter parameter-declaration type-parameter: class ...opt identifieropt class identifieropt= type-id typename ...opt identifieropt typename identifieropt= type-id template < template-parameter-list > class ...opt identifieropt template < template-parameter-list > class identifieropt= idexpression optの後の要素は省略可能
  163. 163. Template Template Parameters template <class Container> class hoge;  では hoge<std::vector<int>> h;  は出来ても hoge<std::vector> h;  は出来ない
  164. 164. Template Template Parameters 要するにテンプレートクラス自体などを受 け取る為のテンプレートパラメータ
  165. 165. Template Template Parameters アキラさんのブログに分かりやすい例が あったので引用する template <class T> class vector; template <template<class> class Container> class hoge { Container<int> c; }; hoge<vector> h; // OK
  166. 166. Template Template Parameters template < template-parameter-list > class ...opt identifieropt template < template-parameter-list > class identifieropt= idexpression このようにして受け取れる optにellipsisがあるように可変長引数でも可能
  167. 167. Template Template Parameters Template Template Parametersまとめ ・テンプレートクラス等を受け取る場合に  使う為のTemplate Parameter
  168. 168. おしながき 1. Templateの基本確認 2. Template Meta Programmingとは 3. Template Meta Programming入門 4. Template Meta Programming応用 5. その他付録 6. まとめ 7. 質疑応答
  169. 169. Template Meta Programmingとは お疲れ様でした、テンプレートの機能をひ と通り確認するだけで絶望的な量でした これでも相当、本当に沢山端折って説明し たので規格自体はこの数倍の量があります
  170. 170. Template Meta Programmingとは がっかりしたところで、初心者も最低限の 知識が付いたと思うので二章に入ります
  171. 171. Template Meta Programmingとは Template Meta Programmingとは何か
  172. 172. Template Meta Programmingとは テンプレートを利用して、型や値に関する 演算・処理をコンパイル時に行う技法 よく省略してTMPと呼ばれる
  173. 173. Template Meta Programmingとは テンプレートはコンパイル時に処理されるの でこの技法ではコンパイル時に計算が出来る
  174. 174. Template Meta Programmingとは この技法を用いた機能が標準ライブラリに もtype_traitsをはじめ多く含まれている
  175. 175. Template Meta Programmingとは 大きく分けて ・型を処理するもの ・値(として型)を処理するもの に分けられる
  176. 176. Template Meta Programmingとは 型を処理するものはたいてい template<class T>  のような型パラメータを使って型を操作して いく
  177. 177. Template Meta Programmingとは 値(として型)を処理するものはたいてい template<int N>  のような非型パラメータを使って値(として 使えるような型)を操作していく
  178. 178. Template Meta Programmingとは 次章で実例を見ていくとしましょう
  179. 179. おしながき 1. Templateの基本確認 2. Template Meta Programmingとは 3. Template Meta Programming入門 4. Template Meta Programming応用 5. その他付録 6. まとめ 7. 質疑応答
  180. 180. Template Meta Programming入門 この章では実例を見ていく 初心者向けに最も単純な例から取り上げる
  181. 181. Template Meta Programming入門 例1 型を受け取って値を返すもの
  182. 182. Template Meta Programming入門 例えばある2つの型を比較して 同じ型であればtrue 異なる型であればfalse を得たい
  183. 183. Template Meta Programming入門 そのような機能を提供する std::is_same が標準ライブラリにはある
  184. 184. Template Meta Programming入門 これは以下のように使う std::is_same<int, int>::value // true std::is_same<int, unsigned int>::value // false
  185. 185. Template Meta Programming入門 実装はどうなっているのか
  186. 186. Template Meta Programming入門 宣言 template<class T, class U> struct is_same;  ただ2つの型を受け取る
  187. 187. Template Meta Programming入門 問題はどうやって判別して結果を変えるか
  188. 188. Template Meta Programming入門 答え : 部分特殊化を使う
  189. 189. Template Meta Programming入門 template<class T, class U> // different types struct is_same { static constexpr auto value = false; }; template<class T> // same type struct is_same<T, T> { static constexpr auto value = true; };
  190. 190. Template Meta Programming入門 template<class T> struct is_same<T, T> { static constexpr auto value = true; }; 両辺に同じ型が渡された場合のみこちらの 定義が使われる
  191. 191. Template Meta Programming入門 条件分岐 → 部分特殊化を使う
  192. 192. Template Meta Programming入門 結果の返し方 静的なメンバ定数を定義する static constexpr auto value = true; // ただの静的定数でも良い そうすれば、 is_same<int, int>::valueのようにして得られる
  193. 193. Template Meta Programming入門 このような実質関数として働くようなテン プレートクラスはmeta functionと呼ばれる
  194. 194. Template Meta Programming入門 例2 値を受け取って型を返すもの
  195. 195. Template Meta Programming入門 条件式によって違う型を返すメタ関数
  196. 196. Template Meta Programming入門 std::conditionalと同じ働きのメタ関数 template<bool B, class T, class F> // true struct conditional { using type = T; }; template<class T, class F> // false struct conditional<false, T, F> { using type = F; }; 型を返す場合はメンバ型を定義してやる typename conditional<true, int, char>::type // int
  197. 197. Template Meta Programming入門 例3 非型テンプレートパラメータによる演算
  198. 198. Template Meta Programming入門 template<int X, int Y> struct add { static constexpr auto value = X + Y; }; add<1, 2>::value // 3 非型パラメータを用いてコンパイル時に演算
  199. 199. Template Meta Programming入門 発展例 階乗の計算
  200. 200. Template Meta Programming入門 template<int i> struct fact { static constexpr auto value = i * fact<i - 1>::value; }; template<> struct fact<1> // 1の場合 { static constexpr auto value = 1; }; 階乗の計算ではvalueの定義にfact<i - 1>::valueを利用するこ とで再帰を実現する
  201. 201. Template Meta Programming入門 template<> struct fact<1> // 1の場合 { static constexpr auto value = 1; }; 1の部分特殊化が無いと再帰が止まらなくなる事に注意する
  202. 202. Template Meta Programming入門 注意 template<int i> struct fact { static constexpr auto value = i > 1? i * fact<i - 1>::value : 1; // 再帰が止まらない }; 三項演算子はtrueの場合も両辺の型の等価性を確認するた めに両辺ともインスタンス化しようとするので、再帰が止 まらない(trueでもfact<i - 1>::valueをインスタンス化する)
  203. 203. Template Meta Programming入門 余談 インスタンス化を遅らせて出来る限り型のまま処理するこ とで部分特殊化無しで実装出来る場合もある template<std::size_t i> struct fact { static constexpr auto value = i * std::conditional< (i > 1), fact<i - 1>, std::integral_constant<std::size_t, 1> >::type::value; };  これは再帰が止まる conditionalの両辺をメタ関数にして遅延評価させる
  204. 204. Template Meta Programming入門 まとめ1 メタ関数には単純な例だけでも 入力として ・値を受け取るもの ・型を受け取るもの 出力として ・値を返すもの ・型を返すもの がある
  205. 205. Template Meta Programming入門 まとめ2 条件分岐 ・クラステンプレートの部分特殊化を使う (後でenable_if等も取り上げる) 結果の返し方 ・型を返すならばメンバ型を定義する ・値を返すならば静的メンバ定数を定義する 名前は慣習として型であればtype、値であればvalueを使う
  206. 206. Template Meta Programming入門 補足 コンパイル時にエラーチェックさせる
  207. 207. Template Meta Programming入門 配列の要素数は正の値であるべきだ template<class T, std::size_t N, bool = (N > 0)> struct array; // 実装無し template<class T, std::size_t N> struct array<T, N, true> { // 実装 }; array<int , 0> a; // 実装が無いのでコンパイルエラーになる このような不正値に対して意図的にコンパイルエラーに出 来るようなコードを書く技法は良く使われる
  208. 208. Template Meta Programming入門 template<class T, std::size_t N, bool = (N > 0)> 比較演算子は括弧で囲む必要がある std::vector<std::vector<int>>のようなネストされたテンプ レートが>>演算子に解釈される問題はC++11以降では平気
  209. 209. Template Meta Programming入門 補足 static_assert
  210. 210. Template Meta Programming入門 コンパイル時アサート static_assert(fact<6>::value == 720, ""); コンパイル時に計算可能な値に対して用いる trueであれば無出力 falseであればコンパイルエラーになる 1番目の引数に条件式 2番目の引数にエラー時のメッセージを渡す 当然、実行時計算されるような値を渡すと失敗扱い
  211. 211. おしながき 1. Templateの基本確認 2. Template Meta Programmingとは 3. Template Meta Programming入門 4. Template Meta Programming応用 5. その他付録 6. まとめ 7. 質疑応答
  212. 212. Template Meta Programming応用 1. 関連知識をおさえる 2. 実践(有用なイディオムと例)
  213. 213. Template Meta Programming応用 これからTMPの応用に入る その前に関連知識を知っておく
  214. 214. Template Meta Programming応用 ・constexpr ・decltype ・SFINAE
  215. 215. Template Meta Programming応用 補足 constexpr
  216. 216. Template Meta Programming応用 C++11のconstexprに関して軽く説明する 私は陶芸家ではないので今回は深入りはしない constexprに関して深く知りたい場合は ・中3女子でもわかる!constexpr ・中3女子が教える本当に気持ちのいい  constexpr ・constexpr中3女子テクニック などの有益な情報の載ったスライドがWeb上に公開されて いるので各自Web上で検索して読むなどすると良い
  217. 217. Template Meta Programming応用 TMPにおける値の計算は整数しか扱えないと いう弱点がある (浮動小数点を無理矢理エミュレートしようとする人は居るが…) (また、一応ratioのようなものもあるが…) またコンパイル時にしか使えない int a = 0; add<a, 1>::value; // エラー、aは実行時オブジェクト
  218. 218. Template Meta Programming応用 C++03やconstexpr非対応のコンパイラの場 合はTMPを使うが、そうでない場合はただ 値を計算して、値を返すだけのようなメタ関 数はconstexpr関数で実装した方が好ましい 事も多いと思われる
  219. 219. Template Meta Programming応用 // コンパイル時に計算可能 template<class T> constexpr T add(T x, T y) { return x + y; } 見慣れた関数の形で実装出来る 実行時にも共通のインタフェースで使える 浮動小数点もOK
  220. 220. Template Meta Programming応用 次のような式はconstant expressionsと呼ばれる。(Constant expressionはコンパイル時に評価され得る) constant-expression: conditional-expression 以降の条件部分はかなり細かいので、発表では適当に流す ので各自確認しておいて欲しい 次ページ以降の条件に当てはまる場合、constexprにはなれ ない
  221. 221. Template Meta Programming応用 条件 ・this (非静的メンバ関数の本体に暗黙の変換の結果を含む、クラスメンバアク セス式の後置式、として表れていない場合) ・リテラルクラスのconstexprコンストラクタとconstexpr関数以外の関数呼び出 し(オーバーロードの解決は普段通り適用される) ・constexpr関数やconstexprコンストラクタの定義の外での未定義動作の constexpr関数や、未定義動作のconstexprコンストラクタの呼び出し
  222. 222. Template Meta Programming応用 条件 ・constant expressionを生成しないような引数を用いてのconstexpr関数の呼び出 し 例 constexpr const int* addr(const int& ir) { return &ir; } // OK static const int x = 5; constexpr const int* xp = addr(x); // OK constant expressionなアドレス constexpr const int* tp = addr(5); // エラー 一時アドレスの取得はconstant expressionではない
  223. 223. Template Meta Programming応用 条件 ・constant expressionを生成しないような引数による、初期化リストのみからな るconstexprコンストラクタの呼び出し 例 int x; // not constant struct A { constexpr A(bool b) : m(b?42:x) { } int m; }; constexpr int v = A(true).m; // OK constexpr int w = A(false).m; // エラー mの初期化に用いられるxが定数でない
  224. 224. Template Meta Programming応用 条件 ・constexpr関数又はconstexprコンストラクタの再帰呼び出しが処理系の定義す る制限を超える場合(Annex Bを参照) Annex BにおいてRecursive constexpr function invocations [512].と定義されている ・数学上定義されないような値、又は特定の型で扱える範囲外のその型の値。 ・ラムダ式 ・次の場合を除く左辺値から右辺値への変換  ・constant expressionで事前に初期化された非volatileなconstオブジェクトを参 照する整数型のglvalue又はenum  ・constexpr修飾で定義された、非volatileのオブジェクトかそのようなサブオ ブジェクトを参照するリテラル型のglvalue  ・constant expressionで初期化された寿命の尽きていない一時オブジェクトを 参照するリテラル型のglvalue
  225. 225. Template Meta Programming応用 条件 ・非activeなunionのメンバやサブオブジェクトを参照するglvalueに適用される左 辺値から右辺値への変換 ・constant expressionによって初期化されていない状態の値やデータメンバ参照 を参照するid-expression ・dynamic cast ・reinterpret_cast ・擬似destructorの呼び出し ・インクリメント及びデクリメント操作 ・多態クラス型に対するtypeid式 ・new式 ・delete式
  226. 226. Template Meta Programming応用 条件 ・ポインタ同士の減算 ・結果が不特定な場所での比較に関連するような演算子(rational or equality operator) ・代入及び複合代入 ・throw式
  227. 227. Template Meta Programming応用 更に補足 実行時計算とコンパイル時計算の浮動小数点 演算の精度は異なる場合がある
  228. 228. Template Meta Programming応用 規格では浮動小数点の演算精度に関して制限を課さないの で、コンパイル時と実行時における同じ式の浮動小数点演 算の結果が同じである保証は無い (N3337 5.19 Constant expressions) bool f() { char array[1 + int(1 + 0.2 - 0.1 - 0.1)]; // 必ずコンパイル時に計算される int size = 1 + int(1 + 0.2 - 0.1 - 0.1); // 実行時に計算されるかもしれない return sizeof(array) == size; } f()の結果がtrueであるかfalseであるかは未定義である。
  229. 229. Template Meta Programming応用 ・整数演算しか出来ないTMPに比べ  constexprは浮動小数点演算もコンパイル  時に出来る ・コンパイル時計算にしか使えないTMPに比  べconstexprは実行時計算にも使える ・逆に型に関する処理はTMPでしか実現出  来ない(TMPの独壇場)
  230. 230. Template Meta Programming応用 補足 decltype
  231. 231. Template Meta Programming応用 decltype イメージとしてはsizeofの型バージョン
  232. 232. Template Meta Programming応用 decltype The type denoted by decltype(e) is defined as follows: — if e is an unparenthesized id-expression or an unparenthesized class member access (5.2.5), decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed; — otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e; — otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e; — otherwise, decltype(e) is the type of e.
  233. 233. Template Meta Programming応用 decltype if e is an unparenthesized id-expression or an unparenthesized class member access ... 要するにexpressionが括弧で囲まれていないような decltype(expression)の形のものの場合
  234. 234. Template Meta Programming応用 例 char a; decltype(a); // char int b = 1; int& c = b; decltype(c); // int& const int* d; decltype(d); // const int*
  235. 235. Template Meta Programming応用 例 struct a_type { using type = int; }; a_type a; decltype(a); // a_type decltype(a)::type; // int void f(int); decltype(f); // void (int)
  236. 236. Template Meta Programming応用 例 void f(int); void f(double); decltype(f); // Error 関数に複数のオーバーロードがあるとダメ
  237. 237. Template Meta Programming応用 例 int f(); decltype(f()); // int 関数の戻り値の型も取れる decltype(e)のeのexpressionが評価されることはないので関数 の定義は必要ない(TMPにおいて重要)
  238. 238. Template Meta Programming応用 decltype decltype((expression))の形のものの場合
  239. 239. Template Meta Programming応用 decltype otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e; decltype((expression))のような括弧で囲まれ たもので、かつxvalueの場合T&&になる xvalueはrvalue referenceを返す関数の呼び出しとそれに準ず るもののイメージ(std::moveなども含まれる)
  240. 240. Template Meta Programming応用 decltype otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e; decltype((expression))のような括弧で囲まれ たもので、かつlvalueの場合T&になる
  241. 241. Template Meta Programming応用 decltype otherwise, decltype(e) is the type of e. それ以外(prvalue等)はeの型 例 decltype(1); // int decltype("hello,world"); // const char[12]
  242. 242. Template Meta Programming応用 decltypeまとめ ・decltypeを使うとオブジェクトや関数の戻  り値の型を得る事が出来る ・decltypeの結果は括弧の有無で変わる
  243. 243. Template Meta Programming応用 補足 SFINAE
  244. 244. Template Meta Programming応用 SFINAE Substitution failure is not an error
  245. 245. Template Meta Programming応用 テンプレートの置き換えに失敗してもすぐ にはエラーにならず他の候補を探す 必修知識だがC++入門書には多分載ってない (結果として知らない人も居る印象)
  246. 246. Template Meta Programming応用 言葉より実例を見るほうが早い
  247. 247. Template Meta Programming応用 struct Test { typedef int foo; }; template <typename T> void f(typename T::foo) {} // Definition #1  template <typename T> void f(T) {} // Definition #2  int main() { f<Test>(10);  f<int>(10);  }
  248. 248. Template Meta Programming応用 struct Test { typedef int foo; }; template <typename T> void f(typename T::foo) {} // Definition #1  template <typename T> void f(T) {} // Definition #2  int main() { f<Test>(10);  f<int>(10);  }
  249. 249. Template Meta Programming応用 struct Test { typedef int foo; }; template <typename T> void f(typename T::foo) {} // Definition #1  template <typename T> void f(T) {} // Definition #2  int main() { f<Test>(10);  f<int>(10);  }
  250. 250. Template Meta Programming応用 struct Test { typedef int foo; }; template <typename T> void f(typename T::foo) {} // Definition #1 定義にマッチする template <typename T> void f(T) {} // Definition #2  int main() { f<Test>(10); // Call #1.  f<int>(10);  }
  251. 251. Template Meta Programming応用 struct Test { typedef int foo; }; template <typename T> void f(typename T::foo) {} // Definition #1 int::fooは存在しない template <typename T> void f(T) {} // Definition #2  int main() { f<Test>(10); // Call #1.  f<int>(10);  }
  252. 252. Template Meta Programming応用 struct Test { typedef int foo; }; template <typename T> void f(typename T::foo) {} // Definition #1 呼出候補から外れる template <typename T> void f(T) {} // Definition #2  int main() { f<Test>(10); // Call #1.  f<int>(10);  }
  253. 253. Template Meta Programming応用 struct Test { typedef int foo; }; template <typename T> void f(typename T::foo) {} // Definition #1 エラーにはならない template <typename T> void f(T) {} // Definition #2 定義にマッチする int main() { f<Test>(10); // Call #1.  f<int>(10); // Call #2.  }
  254. 254. Template Meta Programming応用 このようなルールをSFINAEと呼ぶ 条件分岐、エラーチェック等を実現出来る (例は後述)
  255. 255. Template Meta Programming応用 1. 関連知識をおさえる 2. 実践(有用なイディオムと例)
  256. 256. Template Meta Programming応用 関連知識をおさえたところでいよいよ応用 として実用的なイディオム等を見ていく
  257. 257. Template Meta Programming応用 ・Variadic templates   可変長引数テンプレートを扱う ・enable_if   SFINAEによる条件分岐 ・index_tuple, index_range (index_sequence)   整数列パラメータパックの生成と利用 ・Expression Template(ET)  式テンプレート
  258. 258. Template Meta Programming応用 Variadic templates  可変長引数テンプレートを扱う
  259. 259. Template Meta Programming応用 要素の追加 型リストを保持する単純なクラス template<class... Types> struct list { template<class Type> struct push_back { using type = list<Types..., Type>; // これでOK }; };
  260. 260. Template Meta Programming応用 要素の追加 例えばlist<int, char>::push_back<double>::typeのとき Types...はint, charに展開され、Typeはdoubleであるから list<Types..., Type>はlist<int, char, double>
  261. 261. Template Meta Programming応用 要素の追加 template<class... Types> struct list { template<class Type> struct push_front { using type = list<Type,Types...>; // これでOK }; }; push_frontも同様に可能
  262. 262. Template Meta Programming応用 要素の削除 template<class... Types> struct list { private: template<class Type, class... Types2> struct pop_front_impl { using type = list<Types2...>; }; public: struct pop_front { using type = typename pop_front_impl<Types...>::type; }; };
  263. 263. Template Meta Programming応用 要素の削除 template<class Type, class... Types2> struct pop_front_impl { using type = list<Types2...>; }; 複数受け取ったパラメータのうちの最初の1つだけTypeに入 り、残りは全てTypes2に入る
  264. 264. Template Meta Programming応用 要素の削除 pop_backだけは簡単にはいかない 実装も他の操作に比べ面倒、計算コストもかかる template<class... Types2, class Type> // エラー、可変長引数テン プレートはテンプレートパラメータのうち最後でなければ ならない 再帰的な実装など工夫が必要
  265. 265. Template Meta Programming応用 enable_if  SFINAEによる条件分岐
  266. 266. Template Meta Programming応用 enable_if ・SFINAEを利用した条件分岐を手助けする  イディオム ・標準ライブラリにstd::enable_ifがある
  267. 267. Template Meta Programming応用 enable_if template<bool B, class T = void> struct enable_if {}; template<class T> struct enable_if<true, T> { typedef T type; }; つまり条件を満たした場合のみ std::enable_if<条件>::type が定義される(SFINAEに利用出来る)
  268. 268. Template Meta Programming応用 例 template<class T> T foo2 ( T t, typename std::enable_if<std::is_integral<T>::value>::type* = 0) { return t; } Tが整数型だった場合のみ呼び出し可能な関数 Tが非整数型なら呼出候補から外される (もし呼出候補が1つも見つからなければコンパイルエラー) 不正な型の引数が渡される事を防止出来る
  269. 269. Template Meta Programming応用 例 template<class T, class Enable = void> class A; // undefined template<class T> class A<T, typename std::enable_if<std::is_floating_point<T>::value>::type> { }; 条件を満たした場合のみ構築可能なクラスを部分特殊化で 実現する SFINAEの対象は関数に限られたものではない
  270. 270. Template Meta Programming応用 もっとenable_if  enabler idiom
  271. 271. Template Meta Programming応用 従来のenable_ifではオーバーロード出来ない template<typename T, typename Enable = typename std::enable_if <std::is_integral<T>::value>::type> void f(T); template<typename T, typename Enable = typename std::enable_if<std::is_pointer<T>::value>::type> void f(T); // デフォルト引数が異なるだけの再定義はダメ
  272. 272. Template Meta Programming応用 type-parameterでのオーバーロードは厳しい
  273. 273. Template Meta Programming応用 そこで以下のような宣言を行う extern void * enabler;
  274. 274. Template Meta Programming応用 extern void * enabler; の定義は必要ない enablerはextern修飾されているので外部リン ケージを持つ ということは
  275. 275. non-type template-parameter non-type template-parameterに渡せるもの 外部リンケージのあるオブジェクト ・extern修飾されたもの
  276. 276. Template Meta Programming応用 これはオーバーロード出来る template<typename T, typename std::enable_if< std::is_integral<T>::value>::type *& = enabler> void f(T); template<typename T, typename std::enable_if< std::is_pointer<T>::value>::type *& = enabler> void f(T);
  277. 277. Template Meta Programming応用 template<typename T, typename std::enable_if< std::is_integral<T>::value>::type *& = enabler> void f(T); enable_ifを非型パラメータとして用いているのがポイント (参照型は非型パラメータになれる) enablerは外部リンケージを持つので非型パラメータに渡す 事が出来る
  278. 278. Template Meta Programming応用 わざわざ使わなくても十分なケースが多い しかし、必要になることもある
  279. 279. Template Meta Programming応用 index_tuple, index_range (integer_sequence)  整数列パラメータパックの生成と利用
  280. 280. Template Meta Programming応用 index_tuple idiomなどと呼ばれる ・整数列のパラメータパックを生成するイ  ディオム ・C++14からはstd::integer_sequenceとして  同様の機能が標準ライブラリ入り ・インデックスアクセス可能なデータ構造  の効率の良い要素の走査、リスト内包表  記相当の処理の実現
  281. 281. Template Meta Programming応用 ・整数列パラメータを保持する型 ・整数列パラメータを生成するヘルパメタ  関数 のセットで用いられる
  282. 282. Template Meta Programming応用 例えばNを正の整数としたとき index_range<0, N>::typeが index_tuple<0,1,2,3, ..., N-1>  と同じ型になるように実装する
  283. 283. Template Meta Programming応用 実装例(簡単でクソなO(N)オーダーでの実装) template<std::size_t... Indices> struct index_tuple {}; template<std::size_t step, std::size_t last, class result = index_tuple<>, bool flag = step >= last> struct index_range { using type = result; }; template<std::size_t step, std::size_t last, std::size_t... Indices> struct index_range<step, last, index_tuple<Indices...>, false> : index_range<step + 1, last, index_tuple<Indices..., step>> {};
  284. 284. Template Meta Programming応用 実装例(簡単でクソなO(N)オーダーでの実装) template<std::size_t... Indices> struct index_tuple {}; template<std::size_t step, std::size_t last, class result = index_tuple<>, bool flag = step >= last> struct index_range { using type = result; }; template<std::size_t step, std::size_t last, std::size_t... Indices> struct index_range<step, last, index_tuple<Indices...>, false> : index_range<step + 1, last, index_tuple<Indices..., step>> {};
  285. 285. Template Meta Programming応用 template<std::size_t... Indices> struct index_tuple {}; 整数列パラメータを保持する型 例 index_tuple<0,1,2,3,4,5> // 0,1,2,3,4,5を保持
  286. 286. Template Meta Programming応用 index_rangeは整数列パラメータを生成する ヘルパメタ関数 ・結果を返す定義(デフォルト定義) ・整数列パラメータを生成するフローの為  の部分特殊化 の2つの定義がある
  287. 287. Template Meta Programming応用 実装例(簡単でクソなO(N)オーダーでの実装) template<std::size_t... Indices> struct index_tuple {}; template<std::size_t step, std::size_t last, class result = index_tuple<>, bool flag = step >= last> struct index_range { using type = result; }; template<std::size_t step, std::size_t last, std::size_t... Indices> struct index_range<step, last, index_tuple<Indices...>, false> : index_range<step + 1, last, index_tuple<Indices..., step>> {};
  288. 288. Template Meta Programming応用 結果を返すデフォルト定義 template< std::size_t step, std::size_t last, class result = index_tuple<>, bool flag = first >= last > struct index_range { using type = result; };
  289. 289. Template Meta Programming応用 パラメータの解説 template<  std::size_t step, // 現在処理している数(呼出は初期値を渡す) std::size_t last, // 範囲の終わり(さきほどのN) class result = index_tuple<>, // 結果型(デフォでindex_tuple<>) bool flag = first >= last // 再帰の終了条件 > struct index_range { using type = result; // 型を定義して結果を返す };
  290. 290. Template Meta Programming応用 実装例(簡単でクソなO(N)オーダーでの実装) template<std::size_t... Indices> struct index_tuple {}; template<std::size_t step, std::size_t last, class result = index_tuple<>, bool flag = step >= last> struct index_range { using type = result; }; template<std::size_t step, std::size_t last, std::size_t... Indices> struct index_range<step, last, index_tuple<Indices...>, false> : index_range<step + 1, last, index_tuple<Indices..., step>> {};
  291. 291. Template Meta Programming応用 生成フローの定義 template< std::size_t step, // 現在処理している数 std::size_t last, // 範囲の終わり std::size_t... Indices // 結果の整数列パラメータ > struct index_range< step, last, index_tuple<Indices...>, false>  : index_range<step + 1, last, index_tuple<Indices..., step>> {};
  292. 292. Template Meta Programming応用 生成フローの定義 template< std::size_t step, // 現在処理している数 std::size_t last, // 範囲の終わり std::size_t... Indices // 結果の整数列パラメータ > struct index_range< step, last, index_tuple<Indices...>, false> // falseで特殊化 : index_range<step + 1, last, index_tuple<Indices..., step>> {};
  293. 293. Template Meta Programming応用 デフォルト定義における以下の部分 bool flag = first >= last // 再帰の終了条件 がfalseになったときだけ部分特殊化された定義が使われる すなわち生成フローの定義が使われる
  294. 294. Template Meta Programming応用 生成フローの定義 template< std::size_t step, // 現在処理している数 std::size_t last, // 範囲の終わり std::size_t... Indices // 結果の整数列パラメータ > struct index_range< step, last, index_tuple<Indices...>,  false> // falseで特殊化 : index_range<step + 1, last, index_tuple<Indices..., step>> {};
  295. 295. Template Meta Programming応用 生成フローの定義 template< std::size_t step, // 現在処理している数 std::size_t last, // 範囲の終わり std::size_t... Indices // 結果の整数列パラメータ > struct index_range< step, last, index_tuple<Indices...>, // 結果型はindex_tupleにIndicesを渡す false> // falseで特殊化 : index_range<step + 1, last, index_tuple<Indices..., step>> {};
  296. 296. Template Meta Programming応用 template< std::size_t step, // 現在処理している数 std::size_t last, // 範囲の終わり std::size_t... Indices // 結果の整数列パラメータ > struct index_range< step, last, index_tuple<Indices...>, // 結果型はindex_tupleにIndices渡す false> // falseで特殊化 : index_range<step + 1, last, index_tuple<Indices..., step>> // パラメータ違いのindex_rangeを継承している {};
  297. 297. Template Meta Programming応用 テンプレートパラメータ違いの自分自身を 継承すること : index_range<step + 1, last, index_tuple<Indices..., step>>  メタ関数における再帰を意味する テンプレートパラメータは関数の引数相当
  298. 298. Template Meta Programming応用 : index_range<step + 1, last, index_tuple<Indices..., step>>  この部分ではstepを1進め 可変長引数テンプレートパラメータの要素 にstepを追加して再帰する index_tupleに渡す引数を増やしながら再帰している
  299. 299. Template Meta Programming応用 結果を返すデフォルト定義に戻る template< std::size_t step, std::size_t last, class result = index_tuple<>, // (index_tuple<Indices..., step>) bool flag = first >= last // stepがlastに達した時点で再帰が止まる > struct index_range { using type = result; // 結果型 };
  300. 300. Template Meta Programming応用 実用例
  301. 301. Template Meta Programming応用 配列クラスと値nを受けとり、全要素にnを加えた値の要素を持つ配列クラスを 返す関数iota template<class T, std::size_t N, std::size_t... Indices> constexpr auto iota_impl(const array<T, N> arr, const T n, index_tuple<Indices...>) -> array<T, N> { return array<T, N>{{(arr[Indices] + n)...}}; } template<class T, std::size_t N> constexpr auto iota(const array<T, N> arr, const T n) -> array<T, N> { return iota_impl(arr, n, typename index_range<0, N>::type()); } constexpr array<int, 9> arr1{{1,2,3,4,5,6,7,8,9}}; // 配列クラスのオブジェクト constexpr auto arr2 = iota(arr1, 1);  // iotaには配列クラスのオブジェクトと値nを渡してやる //結果としてarray<int, 9>{{2,3,4,5,6,7,8,9,10}}が欲しい
  302. 302. Template Meta Programming応用 template<class T, std::size_t N, std::size_t... Indices> constexpr auto iota_impl(const array<T, N> arr, const T n, index_tuple<Indices...>) -> array<T, N> { return array<T, N>{{(arr[Indices] + n)...}}; } template<class T, std::size_t N> constexpr auto iota(const array<T, N> arr, const T n) -> array<T, N> { return iota_impl(arr, n, typename index_range<0, N>::type()); } constexpr array<int, 9> arr1{{1,2,3,4,5,6,7,8,9}}; constexpr auto arr2 = iota(arr1, 1); // array<int, 9>{{2,3,4,5,6,7,8,9,10}} Tはintに、Nは9に推論される
  303. 303. Template Meta Programming応用 template<class T, std::size_t N, std::size_t... Indices> constexpr auto iota_impl(const array<T, N> arr, const T n, index_tuple<Indices...>) -> array<T, N> { return array<T, N>{{(arr[Indices] + n)...}}; } template<class T, std::size_t N> constexpr auto iota(const array<T, N> arr, const T n) -> array<T, N> { return iota_impl(arr, n, typename index_range<0, N>::type()); } constexpr array<int, 9> arr1{{1,2,3,4,5,6,7,8,9}}; constexpr auto arr2 = iota(arr1, 1); // array<int, 9>{{2,3,4,5,6,7,8,9,10}} この場合N = 9であるからindex_range<0, 9>::typeになる
  304. 304. Template Meta Programming応用 template<class T, std::size_t N, std::size_t... Indices> constexpr auto iota_impl(const array<T, N> arr, const T n, index_tuple<Indices...>) -> array<T, N> { return array<T, N>{{(arr[Indices] + n)...}}; } template<class T, std::size_t N> constexpr auto iota(const array<T, N> arr, const T n) -> array<T, N> { return iota_impl(arr, n, typename index_range<0, N>::type()); } constexpr array<int, 9> arr1{{1,2,3,4,5,6,7,8,9}}; constexpr auto arr2 = iota(arr1, 1); // array<int, 9>{{2,3,4,5,6,7,8,9,10}} index_range<0, 9>::typeはindex_tuple<0,1,2,3,4,5,6,7,8>である
  305. 305. Template Meta Programming応用 template<class T, std::size_t N, std::size_t... Indices> constexpr auto iota_impl(const array<T, N> arr, const T n, index_tuple<Indices...>) -> array<T, N> { return array<T, N>{{(arr[Indices] + n)...}}; } template<class T, std::size_t N> constexpr auto iota(const array<T, N> arr, const T n) -> array<T, N> { return iota_impl(arr, n, typename index_range<0, N>::type()); } constexpr array<int, 9> arr1{{1,2,3,4,5,6,7,8,9}}; constexpr auto arr2 = iota(arr1, 1); // array<int, 9>{{2,3,4,5,6,7,8,9,10}} 結果としてindex_tuple<0,1,2,3,4,5,6,7,8>()がiota_implの引数 として渡される
  306. 306. Template Meta Programming応用 template<class T, std::size_t N, std::size_t... Indices> // Indices is 0,1,2,3,4,5,6,7,8 constexpr auto iota_impl(const array<T, N> arr, const T n, index_tuple<Indices...>) -> array<T, N> { return array<T, N>{{(arr[Indices] + n)...}}; } template<class T, std::size_t N> constexpr auto iota(const array<T, N> arr, const T n) -> array<T, N> { return iota_impl(arr, n, typename index_range<0, N>::type()); } constexpr array<int, 9> arr1{{1,2,3,4,5,6,7,8,9}}; constexpr auto arr2 = iota(arr1, 1); // array<int, 9>{{2,3,4,5,6,7,8,9,10}} このときIndicesは0,1,2,3,4,5,6,7,8に推論される
  307. 307. Template Meta Programming応用 template<class T, std::size_t N, std::size_t... Indices> // Indices is 0,1,2,3,4,5,6,7,8 constexpr auto iota_impl(const array<T, N> arr, const T n, index_tuple<Indices...>) -> array<T, N> { return array<T, N>{{(arr[Indices] + n)...}}; } template<class T, std::size_t N> constexpr auto iota(const array<T, N> arr, const T n) -> array<T, N> { return iota_impl(arr, n, typename index_range<0, N>::type()); } constexpr array<int, 9> arr1{{1,2,3,4,5,6,7,8,9}}; constexpr auto arr2 = iota(arr1, 1); // array<int, 9>{{2,3,4,5,6,7,8,9,10}} 最終的にarray<T, N>{{(arr[Indices] + n)...}}の部分は array<int, 9>{{arr[0] + n, arr[1] + n, (中略)..., arr[8] + n}} という風に展開される
  308. 308. Template Meta Programming応用 基本的にインデックスアクセス可能なデー タ構造であれば適用出来る
  309. 309. Template Meta Programming応用 余談 生成結果のメモ化
  310. 310. Template Meta Programming応用 template<std::size_t First, std::size_t Last> struct index_tuple_memo { static constexpr auto value = typename index_range<First, Last>::type(); }; index_tuple系の生成結果のメモ化を行う試み typename index_range::type()の呼び出し時に index_tuple_memo::valueを代わりに使う事で使いまわす 2回目以降の呼び出しでO(1)が期待出来る
  311. 311. Template Meta Programming応用 ・メモリ使用量が増える可能性 ・コンパイラの最適化によっては無意味 ・逆効果かも 同じ要素数で尚且つ数千要素のtuple展開を何度も行うよう な場合には有効かもしれないが通常は使わなくて良さそう
  312. 312. Template Meta Programming応用 index_rangeの実装には簡単でクソなO(N)オーダーでの実装 の他に有用なO(log2(N))オーダーでの実装法も知られている
  313. 313. Template Meta Programming応用 線形オーダーでは扱える要素数が限られ、生成速度も遅い のでSproutや標準ライブラリで後者の実装が使われている
  314. 314. Template Meta Programming応用 アイデア概要 例えばN = 14のとき Indicesが0,1,2,3,4,5,6であれば index_tuple<Indices..., (Indices + N/2)...>  を展開すれば index_tuple<0,1,2,3,4,5,6,7,8,9,10,11,12,13>  が得られる 現実には実装はもっと面倒だが基本的には、このように前 の結果を利用して要素数を倍々にしていくという考え
  315. 315. Template Meta Programming応用 詳しい実装に関してはsprout::index_rangeなどを見て欲しい
  316. 316. Template Meta Programming応用 Expression Template(ET) 式テンプレート
  317. 317. Template Meta Programming応用 ・式の評価を遅延させる ・余計な一時オブジェクトの生成とコピーの  発生を防ぐ
  318. 318. Template Meta Programming応用 通常、巨大な行列の一時オブジェクトが生 成される演算に対して、演算の結果ではな く演算を表す型オブジェクトを返す
  319. 319. Template Meta Programming応用 行列のA, B, Cの和 A+B+C ETを使わない実装では、A + Bで値を計算し て一時オブジェクトを生成、更に一時オブ ジェクト + Cで値を計算して一時オブジェク トを生成という事が起こりうる その過程で巨大なオブジェクトのコピー、構 築が起こりうる
  320. 320. Template Meta Programming応用 行列のA, B, Cの和 Plus<Plus<Vector<A>,Vector<B>>,Vector<C>> 演算を型として表す、巨大な行列をコピーし たりしなくて済むので、途中式の段階で一 時オブジェクトの生成コストが非常に小さ くなる
  321. 321. Template Meta Programming応用 値はoperator=()が呼ばれた時に初めて評価さ れる
  322. 322. Template Meta Programming応用 参考 ETの簡単な実装法やデメリット等も含めて 紹介されている 日本で一番分かりやすく書いたつもりの Expression Templateの説明 http://d.hatena.ne.jp/Cryolite/20040506 などが分かりやすい
  323. 323. おしながき 1. Templateの基本確認 2. Template Meta Programmingとは 3. Template Meta Programming入門 4. Template Meta Programming応用 5. その他付録 6. まとめ 7. 質疑応答
  324. 324. その他付録 1. TMPとは直接関係ないイディオムなど 2. これからのTMPと関連イディオムなど
  325. 325. その他付録 型を受け取るユーザ定義リテラル
  326. 326. その他付録 整数リテラルと浮動小数点リテラルに限り char...のテンプレート実引数として受け取る ことが出来る
  327. 327. その他付録 template<char...> void operator "" _to_string() {}; 12345_to_string; // template<‘1’,’2’,’3’,’4’,’5’>として渡される 3.14_to_string; // template<‘3’,’.’,’1’,,4>
  328. 328. その他付録 #include <sprout/index_tuple.hpp> template<char last> constexpr auto indices() -> typename sprout::index_range<0, last - '0'>::type { return sprout::index_range<0, last - '0'>::make(); } template<char... last> constexpr auto operator "" _indices() -> decltype(indices<last...>()) { static_assert(sizeof...(last) == 1, ""); return indices<last...>(); } int main() { static_assert(std::is_same<decltype(2_indices), sprout::index_tuple<0,1>>::value, ""); } ユーザ定義リテラルを使ったindex_tupleの生成みたいなサンプル (実際にはchar同士の減算等にはもう少し気を配った方がいい感じがしますが)
  329. 329. その他付録 型文字列の生成に使える ただし整数と浮動小数点のみ ショージキ微妙だが今後に期待
  330. 330. その他付録 private namespace idiom  detail等へのアクセスを制限する
  331. 331. その他付録 namespace tmp {  namespace { // 無名名前空間 namespace detail { // detailへはアクセスされたくない }  void f() { detail::f_impl(); } // publicなインタフェース }  namespace detail {}; // detailのメンバへのアクセスを殺す void f_impl() {} // privateな実装 }  tmp::f(); // OK  tmp::detail::f_impl(); // ルックアップに失敗しエラー
  332. 332. その他付録 無名名前空間が暗黙にusingされる事を逆手に取る detailへのアクセスを殺せるので名前空間スコープで、メタ 関数の内部実装にどうしてもアクセスされたくない場合に は有効
  333. 333. その他付録 1. TMPとは直接関係ないイディオムなど 2. これからのTMPと関連イディオムなど
  334. 334. その他付録 先程取り上げたinteger_sequenceの他にもあ る、C++14(所謂N3690辺り) / C++1y以降に 入ると思われる機能とそれに関連する話 (大雑把に未来の話です) ただしTMPに割と関連しそうなものだけ
  335. 335. その他付録 C++14以降で(ほぼ確実に)入る機能
  336. 336. その他付録 constexprの制限緩和
  337. 337. その他付録 ・副作用、制御構文が使えるようになる ・ポインタ同士の減算が定数式になる など 一部制限が増えている ・a conversion from type cv void * to a pointer-to-object type; C++11ではreinterpret_castが禁止されていたのにvoid*の型 変換が禁止されていなかったが、これもダメに修正された
  338. 338. その他付録 ただし、constexpr関数では相変わらずエラーハンドリング が困難なので 闊に副作用の濫用を行うと、例外安全性を 保つのが難しいので注意が必要 その他、細かい事は規格等を参照して欲しい
  339. 339. その他付録 decltype(auto)
  340. 340. その他付録 decltype(auto)は、式をdecltype()の中に書い たのと同じ挙動になる
  341. 341. その他付録 江添さんの記事が分かりやすい http://cpplover.blogspot.jp/2013/08/decltypeauto.html
  342. 342. その他付録 記事の例のみ引用する int i = 0 ; int && f() ; auto a1 = i ; // int decltype(auto) a2 = i ; // int auto b1 = (i) ; // int decltype(auto) b2 = (i) ; // int & auto c1 = f() ; // int decltype(auto) c2 = f() ; // int &&
  343. 343. その他付録 関数の戻り値などに利用出来る template < typename T, typename U > auto g( T const & t, U const & u ) -> decltype( auto ) // decltype( f( t, u ) )と書かなくて済む { return f( t, u ) ; }
  344. 344. その他付録 ジェネリックラムダ
  345. 345. その他付録 ラムダ式もテンプレート化出来る auto NumElements = []<int N>(auto (&a)[N]) { return N; };
  346. 346. その他付録 Variable Templates  変数テンプレート
  347. 347. その他付録 読んで字の如く、変数をテンプレート化する
  348. 348. その他付録 変数テンプレート template<class T> constexpr T pi = static_cast<T>(3.14); pi<int> == 3; pi<float> == 3.14; 異なる精度の値を得る
  349. 349. その他付録 変数テンプレート template<class T1, T2> constexpr bool is_same_v = std::is_same<T1, T2>::value; is_same_v<int, double>; // false 面倒な::valueを書かずに済む
  350. 350. その他付録 C++1y(ここではC++14よりも後を意味する) 以降で入るかもしれない提案
  351. 351. その他付録 Concepts Lite  軽量コンセプト
  352. 352. その他付録 C++11入りする予定だったConceptの軽量・改良版 幾つかペーパーのようなものが出ている模様
  353. 353. その他付録 プログラマにやさしい構文で型制約を行えるようになる constexpr関数として型制約を定義する案など 使えるようになるのは当分先の話になりそうな気はします
  354. 354. その他付録 N3741 Opaque Alias
  355. 355. その他付録 Strong typedef  ある型から別の型を作る using identifier = access-specifier type-id opaque-definition
  356. 356. その他付録 using age = private int; // intとは別の型として認識される // privateにより暗黙のキャストは許可しない age age1 = static_cast<age>(20); // 明示的なキャストをする age age2 = 18; // Error ageはintではない これまでのtypedefやusingではこのような事は出来ない
  357. 357. その他付録 オーバーロード等も有効になる int f(int); age f(age); 別物として扱われる
  358. 358. その他付録 N3730 Specializations and namespaces
  359. 359. その他付録 ネストされた名前空間を閉じなくても特殊化を書けるよう にする提案
  360. 360. その他付録 namespace A { namespace B { /* ... */ class C { /* ... */ }; } } // 一度名前空間を抜ける namespace std { template<> // 特殊化を書く struct hash<A::B::C> { size_t operator()(A::B::C const &c) { /* ... */ } }; } namespace A { /* Reenter namespace I am using */ namespace B { /* ... */ } }
  361. 361. その他付録 namespace A { namespace B { /* ... */ class C { /* ... */ }; template<> struct ::std::hash<C> { std::size_t operator()(C const &c) { /* ... */ } }; /* ... */ } } このように書けるようになる
  362. 362. その他付録 N3728 Packaging Parameter Packs
  363. 363. その他付録 パラメータパックを保持するための型リストをサポートす る提案 パラメータパックが間違いなく扱いやすくなる 具体例はN3728ペーパー参照
  364. 364. その他付録 N3413 Allowing arbitrary literal types for non-type template parameters
  365. 365. その他付録 非型パラメータとして任意のリテラル型を許容しようとい う提案
  366. 366. その他付録 struct C { constexpr C(int v) : v(v) { } int v; }; template<C c> // !? struct X { int array[c.v]; }; int main() { X<C(42)> x; }  C++の世界の法則が乱れる完全にヤバい提案
  367. 367. その他付録 N3761 Proposing type_at<>
  368. 368. その他付録 パラメータパックのN番目の要素にアクセス する機能のメタ関数を標準に入れる提案
  369. 369. その他付録 簡単な実装案が書かれている 要するにN番目の要素に到達するまで線形再帰する template <unsigned N, typename T, typename ...R> struct type_at { using type = typename type_at<N - 1, R...>::type; }; template <typename T, typename ...R> struct type_at<0, T, R...> { using type = T; };
  370. 370. その他付録 簡単な実装案が書かれている 要するにN番目の要素に到達するまで線形再帰する template <unsigned N, typename T, typename ...R> auto value_at(T&&, R&&... r) -> decltype(auto) { return value_at<N - 1, R...>(std::forward<R>(r)...); } template auto value_at(T&& t, R&&...) -> decltype(auto) { return std::forward<T>(t); }
  371. 371. その他付録 対数オーダーで実装可能なのでAuthorに実装 の改良を提案する意見を送付した
  372. 372. その他付録 対数オーダーでの要素アクセスの実装
  373. 373. その他付録 次のようなメタ関数を用意する template<std::size_t N, class T = void> using make_type_sequence = typename make_type_sequence_impl<N, T>::type; // make N-1 Ts type_sequence<T, T, ..., T> O(log2(N)) implでindex_rangeのように型列を対数オーダーで生成する
  374. 374. その他付録 次のようなメタ関数を用意する template<class T> struct type_wrapper { using type = T; }; ただ型を保持するだけの型
  375. 375. その他付録 template<class T, std::size_t N> struct type_at { private: template<template<class...> class Type, class... Args> static auto impl(type_wrapper<Type<Args...>>) -> typename type_at_impl<N, type_wrapper<Args>...>::type; public: using type = typename decltype(impl(type_wrapper<T>()))::type; };  型リストを持つコンテナ型TとインデックスNを受け取る
  376. 376. その他付録 template<class T, std::size_t N> struct type_at { private: template<template<class...> class Type, class... Args> static auto impl(type_wrapper<Type<Args...>>) -> typename type_at_impl<N, type_wrapper<Args>...>::type; public: using type = typename decltype(impl(type_wrapper<T>()))::type; };  type_wrapperに包んでTをimplに渡す
  377. 377. その他付録 type_wrapperの役割 ・インスタンス化出来ない型も処理出来るようにする
  378. 378. その他付録 type_wrapperの役割 using type = typename decltype(impl(type_wrapper<T>()))::type; 例えばTが template<class...>  struct list;  のようなインスタンス化不可能な型の場合 impl(list())はインスタンス化出来ずエラーになるが impl(type_wrapper<T>())ならばインスタンス化出来て渡せる
  379. 379. その他付録 type_wrapperの役割 ・トップレベルのcv修飾を保持する
  380. 380. その他付録 type_wrapperの役割 impl(type_wrapper<T>())ならば値渡しの際もArgument Deductionにおいて、Tのcv修飾情報が失われずに済む
  381. 381. その他付録 template<class T, std::size_t N> struct type_at { private: template<template<class...> class Type, class... Args> static auto impl(type_wrapper<Type<Args...>>) -> typename type_at_impl<N, type_wrapper<Args>...>::type; public: using type = typename decltype(impl(type_wrapper<T>()))::type; };  template template parameterを使えばテンプレートクラスの 持つ型リストを抽出する事が出来る

×