SlideShare a Scribd company logo
1 of 417
Download to read offline
Template Meta Programming
入門から応用まで

@fimbul11
2013/09/28 C++勉強会 @ tkb #2
自己紹介
twitter : @fimbul11
github : fimbul
University of Tsukuba B3 
専攻 : 情報とメディア技術(mast)
プログラミングとかやってます、歴は2年ちょっとぐらいです
C++とかやってます、歴は1年半ぐらいです
ペン回しとか出来ます、歴は7年ぐらいです
はじめに

このような無名の勉強会に遠方からも多く
の人に来ていただけました、本当にありが
とうございます
おしながき
1. Templateの基本確認
2. Template Meta Programmingとは
3. Template Meta Programming入門
4. Template Meta Programming応用
5. その他付録
6. まとめ
7. 質疑応答
おしながき
1. Templateの基本確認
2. Template Meta Programmingとは
3. Template Meta Programming入門
4. Template Meta Programming応用
5. その他付録
6. まとめ
7. 質疑応答
Templateの基本確認
今日は
・C++未経験者
・C++初心者
・C++初心者(意味深)
・C++中級者及び上級者
・歩くC++規格レベル
・人間C++コンパイラ
など色々な方が居る可能性があるので
Templateの基本確認
今日は
・C++未経験者
・C++初心者
・C++初心者(意味深)
・C++中級者及び上級者
・歩くC++規格レベル
・人間C++コンパイラ
など色々な方が居る可能性があるので
Templateの基本確認
今日は
・C++未経験者
・C++初心者
・C++初心者(意味深)
・C++中級者及び上級者
・歩くC++規格レベル
・人間C++コンパイラ
など色々な方が居る可能性があるので
Templateの基本確認
今日は
・C++未経験者
・C++初心者
・C++初心者(意味深)
・C++中級者及び上級者
・歩くC++規格レベル
・人間C++コンパイラ
など色々な方が居る可能性があるので
Templateの基本確認
今日は
・C++未経験者
・C++初心者
・C++初心者(意味深)
・C++中級者及び上級者
・歩くC++規格レベル
・人間C++コンパイラ
など色々な方が居る可能性があるので
Templateの基本確認
今日は
・C++未経験者
・C++初心者
・C++初心者(意味深)
・C++中級者及び上級者
・歩くC++規格レベル
・人間C++コンパイラ
など色々な方が居る可能性があるので
Templateの基本確認
今日は
・C++未経験者
・C++初心者
・C++初心者(意味深)
・C++中級者及び上級者
・歩くC++規格レベル
・人間C++コンパイラ
など色々な方が居る可能性があるので
Templateの基本確認

ガチ勢の方はお手柔らかにお願いします
Templateの基本確認

初心者は知らないことがあるかも
そうでない人も少しおさらいをしておく
という意味で
Templateの基本確認
規格に基づいて文法などの
Templateの基本を確認する
 
Templateの基本確認
規格に基づいて文法などの
Templateの基本を確認する
むしろややこしいTemplateのルールについて
把握する事こそがTemplate Meta Programming
最大の山場といえます
Templateの基本確認
規格に基づいて文法などの
Templateの基本を確認する
非常に重要な部分であり、templateを使った
経験が少ないとこれだけで十分すぎるぐら
いつらいと思います
Templateの基本確認
・C++11規格に沿う
・ただし細かい部分には触れない
 (各自で規格を確認してほしい
  自分もまる覚えはしていない)
・C++14~の機能(Variable Templates等)
 はその他付録の章で扱う
Templateの基本確認

結構量があるので既に知ってる人は適当に
聞き流しつつ他の作業でもしていて下さい
Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
Template is 何

テンプレートって何ですか?
Template is 何

テンプレートって何ですか?
N3337見ましょう
Template is 何

14 Templates
A template defines a family of classes or
functions or an alias for a family of types.
Template is 何

テンプレートは
クラスや関数、型エイリアスのファミリー
を定義する
Template is 何

確認するまでもなかったかもしれません
次に文法を確認していくことにします
Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
テンプレートの文法
テンプレートの文法を確認する
 
テンプレートの文法
テンプレートの文法を確認する
規格を参照して定義から見ていく
テンプレートの文法
テンプレートの文法を確認する
template-declaration:
template < template-parameter-list > declaration
template-parameter-list:
template-parameter
template-parameter-list , template-parameter
テンプレートの文法
テンプレートの文法を確認する
template-declaration:
template < template-parameter-list > declaration
template-parameter-list:
template-parameter
template-parameter-list , template-parameter
テンプレートの文法

テンプレートは
template < template-parameter-list > declaration
 
として定義される
テンプレートの文法

テンプレートは
template < template-parameter-list > declaration
 
として定義される
テンプレートの文法
template-parameter-listは
template-parameter 又は
template-parameter-list , template-parameter 
として定義される
テンプレートの文法
template-parameter-listは
template-parameter 又は
template-parameter-list , template-parameter 
として定義される
Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
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の後の要素は省略可能
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の後の要素は省略可能
Template parameters
template-parameterは
type-parameter又は
parameter-declaration 
である
Template parameters
template-parameterは
type-parameter又は
parameter-declaration 
である
type-parameter
まずtype-parameterの定義の一部のみ紹介する
type-parameter :
class ...opt identifieropt
class identifieropt= type-id
typename ...opt identifieropt
typename identifieropt= type-id
が付いた要素は省略可能

opt

一見種類が多い
type-parameter
まずtype-parameterの定義の一部のみ紹介する
type-parameter :
class ...opt identifieropt
class identifieropt= type-id
typename ...opt identifieropt
typename identifieropt= type-id
対応する色のもの同士は実質同じ
また = type-idの部分はデフォルト引数の有無
type-parameter

定義の数は一見多いが実際は結構単純
順番に定義の意味を見ていく
type-parameter
この4つにおいてtype-parameterの頭の部分では
classキーワードとtypenameキーワード
は同じ意味
(他の場所では当然意味が違うので注意する、
C++には文脈によって同じキーワードに複数
の意味を持たせる文化がある)
(例えばtemplate template parameterの場合違う)
type-parameter
最も単純なtype-parameterを使ったtemplate例
template<class> (又はtemplate<typename>)
type-parameterのclassとtypenameキーワードは
今後の説明ではclassで統一する
(スライドの都合上、短い方がありがたい)
type-parameter
type-parameter :
class ...opt identifieropt
identifierはtype-parameterの名前
例
template<class Type>
type-parameter
type-parameter :
class ...opt identifieropt = type-id
type-idがデフォルト引数になる
例
template<class Type = int>
何も渡されなければTypeはintになる
type-parameter
関数のデフォルト引数同様に
最初のデフォルト引数を持つパラメータ以降
の全パラメータにデフォルト引数が必要
例
template<class T1 = int, class T2 = int> class A;
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;
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’
type-parameter
例まとめ
template<class> 無名
template<class = int> デフォルト引数有り
template<class Type> 名前有り
template<class Type = int> デフォルト引数有り
template<class T1, class T2> 複数のパラメータ
type-parameter

別の定義は後の章で見るので
ひとまずtype-parameterをこれで終わります
Template parameters

template-parameterは
type-parameter又は
parameter-declaration 
である
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
parameter-declaration

parameter-declarationは
non-type template-parameter 
(非型テンプレートパラメータ)の場合に使う
non-type template-parameter
例を見た方が早い
template<char C>
template<int N>
渡される引数がnon-typeなtemplate-parameter
int Nやchar Cがparameter-declarationにあたる
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
non-type template-parameter

全ての型が
non-type template-parameterに
なれるわけではない
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修飾子が付いたもの)

のいずれかを満たす型であるとき
non-type template-parameter

non-type template-parameterになれる条件は
要するに整数型かポインタ型か左辺値参照
non-type template-parameter
例
template<std::size_t N>
std::size_tは整数型のtypedefなのでwell-formed
class myClass {};
template<myClass Arg>
先程の条件を満たさないクラス等はill-formed
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
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
non-type template-parameter

non-type template-parameterに渡せるものにも
条件がある
non-type template-parameter
non-type template-parameterに渡せるもの
・定数式
・関数のアドレス
・外部リンケージのあるオブジェクト
・静的クラス・メンバのアドレス
non-type template-parameter
non-type template-parameterに渡せるもの
定数式(分類に不安があるが…)
・非型テンプレート引数(先程のNなど)
・コンパイル時定数(constexpr)
 (後で説明する)
・sizeofやsizeof...など
non-type template-parameter

non-type template-parameterに渡せるもの
関数のアドレス
・説明不要、f()などのアドレス
non-type template-parameter

non-type template-parameterに渡せるもの
外部リンケージのあるオブジェクト
・extern修飾されたもの
non-type template-parameter

non-type template-parameterに渡せるもの
静的クラス・メンバのアドレス
・説明不要、そのままの意味
template-parameter

template-parameterに関しては、他にも細かい
事が大量に規定されているので適宜規格を調
べる必要がある
template-parameter
template-parameterまとめ
・テンプレートパラメータには型パラメータ
 と非型パラメータがある
・非型パラメータになるものや渡せるものは
 限られている
Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
Class templates

A class template defines the layout and
operations for an unbounded set of related
types.
Class templates

クラステンプレートは、関連する型(要する
に扱う要素の型が違うだけのクラス群)のレ
イアウトをまとめて定義する
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>は渡した型を扱える
Class templates
クラスメンバテンプレート
class Test {
public:
template<class T>
T f(T arg) { return arg; } // 関数テンプレートは後で取り上
げる
};  

クラスメンバもテンプレートに出来る
operator等もテンプレート化可能
Class templates
非型テンプレートパラメータを使う例
template<std::size_t N>
struct integer { // structも当然テンプレート化可能
static constexpr std::size_t value = N;
}; 
Nの型にconst等は付いていなくても非型テ
ンプレートパラメータは(暗黙に)コンパイル
時に値が決まる定数として扱える
(constexpr修飾された値の初期化にも使える)
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’
Class templates
違法な例を招く行為(当然してはいけない)
template<class T, T v>
struct data {
static constexpr T* get_address() {
return const_cast<T*>(&static_cast<const T&>(v));
}
}; 

このような行為は万死に値する
Class templates

補足事項
Template specializations 
テンプレートの特殊化
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に
ある値が入った状態のものは特殊化されているといえる
Class templates

class template partial specializations
クラステンプレートの部分特殊化
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> {};
Class templates

template<class T1, class T2, int I> class A {}; // unspecialized
template<class T, int I> class A<T, T*, I> {};
このように抽象的なテンプレートパラメータの数を減らし
部分的に具体的要素に置き換えた特殊化を作る事が出来る
Class templates

template<class T1, class T2, int I> class A {}; // unspecialized
template<class T, int I> class A<T, T*, I> {};
部分特殊化されたテンプレートは、条件を満たす場合には
特殊化されていないテンプレートより優先的にマッチする
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において非常に重要
Class templates
また、部分特殊化によっては
template<int N>
struct A;
template<>
struct A<0>;
のようにtemplateの中身が空<>になることも
あるが特に文法上問題無い
Class templates

勿論、型テンプレートパラメータだけでな
く非型テンプレートパラメータも部分特殊
化出来る(例は後の章で登場する)
Class templates

テンプレートの特殊化及び部分特殊化が出
来るケースにも条件がある
Class templates
テンプレートの特殊化が出来るケース
特殊化できる
OK : 名前空間スコープ
NG : クラススコープ
つまりクラスのメンバは特殊化不可能
Class templates
テンプレートの部分特殊化が出来るケース
部分特殊化できる:
OK : クラステンプレート
NG : 関数テンプレート
部分特殊化は非クラスメンバのクラステンプ
レート限定の機能といえる
Class templates
Class templatesまとめ
・クラステンプレートは、 関連する型のレ
 イアウトをまとめて定義する
・名前空間スコープのクラステンプレートの
 み部分特殊化によって実装を切り替え可
Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
Function templates

A function template defines an unbounded set of
related functions.
Function templates

関数テンプレートは、関連する関数(要する
に扱う要素の型が違うだけの関数群)をまと
めて定義する
Function templates
例
template<class T>
T twice(T arg) {
return arg * 2;
}
twice(2); // 4
twice(2.5); // 5.0
整数も浮動小数点も扱える
Function templates

Template argument deduction
テンプレート引数の型推論
Function templates
先程の例
twice(2);
twice(2.5);
twice<int>(2)と書かなくとも適切にint版の
twiceが呼ばれ、twice<double>(2.5)と書かな
くとも適切にdouble版のtwiceが呼ばれた
Function templates

このような引数からテンプレートパラメー
タ型を推論する機能が
Template argument deduction
Function templates

幾つかの例外を除き、渡した型がそのまま
推論される
Function templates
例外1
・配列型(T[N])はポインタ(T*)に変換される
・関数型(R(Args...))は関数ポインタ
 (R(*(Args...))に変換される
Function templates

例外2
・値渡しの場合のみトップレベルのcv修飾子
 が無視される
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型
Function templates
例外2
このような挙動の理由は、値コピーを取る場合、結局元の
オブジェクトの値が変更される可能性が無いためとされる
const int b = 0;
test(b); // (testの中ではbのコピーが扱われるのでbの値自体
が変えられることはない、じゃあコピーするときはconst無
視してもいいんじゃね)…とコンパイラは思う
Function templates

例外2
constと同様にvolatileも無視される
Function templates
例外2
よって値を変更する可能性のある参照やポ
インタ渡しの場合はcv修飾子も保持される
template<class T>
T test(T& arg) { return arg; }
const int b = 0;
test(b); // Tはint& const型
Function templates

例外2
ただし明示的に渡せば、渡した通りになる
const int b = 0;
test<const int>(b); // Tはconst intになる
Function templates
例外2
cv修飾子が無視される可能性があるのは
トップレベルの型のみである
例えばvector<const int>などのconst int部分は
トップレベルではないので無視されない
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が出力される
Function templates

std::integral_constant<T, N>
のようにテンプレートクラスのテンプレー
トパラメータとしてネストされた内部の型
でもTやNとして推論出来る
Function templates

Template argument deductionの規格を厳密に
読んで全てのルールを把握していくだけで尋
常じゃない大変さなので残りは省略します
Function templates

Function template overloading
関数テンプレートのオーバーロード
Function templates
部分特殊化は出来ないが特殊化は出来る
これらはオーバーロードされる
template<class T> void output(T val);
template<> void output(const std::string& val);
Function templates
オーバーロードの解決に関しては省略する
N3337
14.5.6.2 Partial ordering of function templates 
を参照して欲しい
ambiguousになる例など取り上げられている
Function templates
Function templatesまとめ
・関数テンプレートは引数から型を推論し
 てくれる
・特殊化、オーバーロードが可能である
Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
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.
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.
Alias templates

もはや訳すのも面倒なので実例を見る
Alias templates

template <class T>
using add_pointer = typename std::add_pointer< T >::type;
add_pointer<T>はstd::add_pointer< T >::typeと同じ型になる
Alias templates

別にtemplateである必要は無い
using type = int; 
typeはint型の別名として使える、簡単!
Alias templates
typedef int integer;
using integer = int;
は同じ効果
typedefの代わりとして使える
(ただし使えるのはC++11以降)
Alias templates
Template Meta Programmingではtypenameと
か::typeを書かなくて済むようにする為に
使ったりする
template<class T>
using add_p = typename std::add_pointer<T>::type;
add_p<int>; // int*
Alias templates
余談
typedefは指定子である
指定子の順番に意味は無い
typedef int Integer1; (こっちが多分メジャー)
int typedef Integer2; (稀に見かける)
// どちらもOK
int Integer3 typedef;  
// これはダメ
Alias templates

typedef int Integer1; のように
どうしてtypedef A B;の形がメジャーなのか?
Alias templates
次のような例を考える
int typedef type; はOKだが
int* typedef type; はダメ
「*」は、指定子(specifier)ではなく、宣言子
(declarator)のため
Alias templates

結論
多分、typedefを最初に書かない場合には宣
言子が出てきた時に面倒臭いから
Alias templates

後方互換性を気にしなくていいなら正直
typedefよりusingを使うと良いと思います
(個人的にはusingの方が好き)
Alias templates

余談
template structなどの状態のメタ関数では遅延されるタイミ
ングで正格評価される場合がある?(エイリアステンプレー
トにしたところコンパイル時間が大幅に伸びた経験がある)
Alias templates

Alias templatesまとめ
・usingを使う事で型の別名として使える
・typedefと違いテンプレート化出来る
Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
Variadic templates

1. A template parameter pack is a template
parameter that accepts zero or more template
arguments.
Variadic templates

2. A function parameter pack is a function
parameter that accepts zero or more function
arguments.
Variadic templates
つまり、
・可変長引数を取るクラス
・可変長引数を取る関数
の為の可変長引数テンプレート
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の後の要素は省略可能
Variadic templates
先程Template parametersで飛ばした
...opt 
を使う
また、「...」を規格上ellipsisと呼ぶ
先の定義通りデフォルト引数は取れない
Variadic templates

template<class... Types> struct Tuple {}; 
class...の部分は可変長引数テンプレート
その名前はTypes
Variadic templates
template<class... Types> struct Tuple {};
可変長引数テンプレートは0個以上の引数を
好きなだけ受け取れる
勿論、非型テンプレート引数版も可能
template<int... Indices> struct Numbers {};
Variadic templates
template<class... Types> struct Tuple {};
例
Tuple<int, double, char, void*> 
このように好きなだけ渡せる
template<int... Indices> struct Numbers {};
Numbers<1,2,3,4,5>
Variadic templates

このような可変長引数部分の事を
template parameter pack 
と呼ぶ
Variadic templates
例
template<class... Types>
struct List;
template<class Type, Type... Args>
struct Data;
TypesやArgsはTemplate Parameter Pack
Variadic templates
可変長引数テンプレートは基本的には、
template parameterのうち最後でなければな
らない(一部例外がある)
template<class Type, class... Types> // OK
template<class... Types, class Type> // NG
Variadic templates
例外
template<std::size_t... Indices1, std::size_t... Indices2>
void f(index_tuple<Indices1...>, index_tuple<Indices2...>);

・関数の引数の型が持つパラメータパック
 を推論する場合
・特に可変長引数を持つ型の引数を複数受
 け取る場合には複数のパラメータパック
 を持つことが出来る
Variadic templates

pack expansion 
受け取ったパラメータパックを展開する
Variadic templates

可変長引数として受け取ったテンプレート
パラメータパックを使う為には
それを展開する必要がある
Variadic templates

展開はpattern and an ellipsisからなる
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に格納して受け取っている
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
に推論される
Variadic templates

このときTypes...は
int, int, int, int, int, int, int, int, int, int 
に展開される
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& 
に展開される
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&);
と等価になっている
Variadic templates

同様にして関数の引数もparameter packとし
て受け取っている
template<class ResultType, class... Types>
ResultType sum(const Types&... Args);
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になる
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
}
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}になる
Variadic templates

sum<int>(1,2.0,3.5,4,5,6,7,8,9,10);
のように型が異なる要素が混入していてもキャストしながら
展開する事が出来る
Variadic templates
補足
template parameter packの要素数を得るには
sizeof...を使う
sizeof...(Types)
sizeof...(Args)
sizeof...に対してはパックは展開せずに渡す
sizeof...(Types...) // NG
Variadic templates
余談
ピリオドが6つ連続するコードが存在し得る
(多分Sprout等で稀にお目にかかれる)

例
template<class... T>
void f(T......); // なにこれキモイ
Variadic templates
これは前半3つのピリオドがVariadic Templatesの展開、後半3つ
のピリオドがC言語スタイルの可変長引数の...であり、真ん中
のカンマが省略されたもの
template<class... T>
void f(T..., ...); // ただのellipsis, ellipsisにすぎない
に等しいのでビビる必要は無い
Variadic templates
Variadic templatesまとめ
・Variadic TemplatesはTemplate Parameter Packと
 して受け取る
・型パラメータ、非型パラメータを扱える
・型パラメータは関数の引数の型として利用出来る
・非型パラメータは関数の引数として利用出来る
・Template Parameter Packはpattern and ellipsis
 によって展開してから使う
Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
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の後の要素は省略可能
Template Template Parameters
template <class Container>
class hoge; 
では
hoge<std::vector<int>> h; 
は出来ても
hoge<std::vector> h; 
は出来ない
Template Template Parameters

要するにテンプレートクラス自体などを受
け取る為のテンプレートパラメータ
Template Template Parameters
アキラさんのブログに分かりやすい例が
あったので引用する
template <class T>
class vector;
template <template<class> class Container>
class hoge {
Container<int> c;
};
hoge<vector> h; // OK
Template Template Parameters

template < template-parameter-list > class ...opt identifieropt
template < template-parameter-list > class identifieropt= idexpression
このようにして受け取れる
optにellipsisがあるように可変長引数でも可能
Template Template Parameters

Template Template Parametersまとめ
・テンプレートクラス等を受け取る場合に
 使う為のTemplate Parameter
おしながき
1. Templateの基本確認
2. Template Meta Programmingとは
3. Template Meta Programming入門
4. Template Meta Programming応用
5. その他付録
6. まとめ
7. 質疑応答
Template Meta Programmingとは

お疲れ様でした、テンプレートの機能をひ
と通り確認するだけで絶望的な量でした
これでも相当、本当に沢山端折って説明し
たので規格自体はこの数倍の量があります
Template Meta Programmingとは

がっかりしたところで、初心者も最低限の
知識が付いたと思うので二章に入ります
Template Meta Programmingとは

Template Meta Programmingとは何か
Template Meta Programmingとは

テンプレートを利用して、型や値に関する
演算・処理をコンパイル時に行う技法
よく省略してTMPと呼ばれる
Template Meta Programmingとは

テンプレートはコンパイル時に処理されるの
でこの技法ではコンパイル時に計算が出来る
Template Meta Programmingとは

この技法を用いた機能が標準ライブラリに
もtype_traitsをはじめ多く含まれている
Template Meta Programmingとは
大きく分けて
・型を処理するもの
・値(として型)を処理するもの
に分けられる
Template Meta Programmingとは
型を処理するものはたいてい
template<class T> 
のような型パラメータを使って型を操作して
いく
Template Meta Programmingとは
値(として型)を処理するものはたいてい
template<int N> 
のような非型パラメータを使って値(として
使えるような型)を操作していく
Template Meta Programmingとは

次章で実例を見ていくとしましょう
おしながき
1. Templateの基本確認
2. Template Meta Programmingとは
3. Template Meta Programming入門
4. Template Meta Programming応用
5. その他付録
6. まとめ
7. 質疑応答
Template Meta Programming入門

この章では実例を見ていく
初心者向けに最も単純な例から取り上げる
Template Meta Programming入門

例1
型を受け取って値を返すもの
Template Meta Programming入門
例えばある2つの型を比較して
同じ型であればtrue
異なる型であればfalse
を得たい
Template Meta Programming入門

そのような機能を提供する
std::is_same
が標準ライブラリにはある
Template Meta Programming入門

これは以下のように使う
std::is_same<int, int>::value // true
std::is_same<int, unsigned int>::value // false
Template Meta Programming入門

実装はどうなっているのか
Template Meta Programming入門

宣言
template<class T, class U>
struct is_same; 
ただ2つの型を受け取る
Template Meta Programming入門

問題はどうやって判別して結果を変えるか
Template Meta Programming入門

答え : 部分特殊化を使う
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;
};
Template Meta Programming入門
template<class T>
struct is_same<T, T> {
static constexpr auto value = true;
};
両辺に同じ型が渡された場合のみこちらの
定義が使われる
Template Meta Programming入門

条件分岐 → 部分特殊化を使う
Template Meta Programming入門
結果の返し方
静的なメンバ定数を定義する
static constexpr auto value = true;
// ただの静的定数でも良い
そうすれば、
is_same<int, int>::valueのようにして得られる
Template Meta Programming入門

このような実質関数として働くようなテン
プレートクラスはmeta functionと呼ばれる
Template Meta Programming入門

例2
値を受け取って型を返すもの
Template Meta Programming入門

条件式によって違う型を返すメタ関数
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
Template Meta Programming入門

例3
非型テンプレートパラメータによる演算
Template Meta Programming入門
template<int X, int Y>
struct add {
static constexpr auto value = X + Y;
};
add<1, 2>::value // 3
非型パラメータを用いてコンパイル時に演算
Template Meta Programming入門

発展例
階乗の計算
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を利用するこ
とで再帰を実現する
Template Meta Programming入門

template<>
struct fact<1> // 1の場合
{
static constexpr auto value = 1;
};
1の部分特殊化が無いと再帰が止まらなくなる事に注意する
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をインスタンス化する)
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の両辺をメタ関数にして遅延評価させる
Template Meta Programming入門
まとめ1
メタ関数には単純な例だけでも
入力として
・値を受け取るもの
・型を受け取るもの
出力として
・値を返すもの
・型を返すもの
がある
Template Meta Programming入門
まとめ2
条件分岐
・クラステンプレートの部分特殊化を使う
(後でenable_if等も取り上げる)
結果の返し方
・型を返すならばメンバ型を定義する
・値を返すならば静的メンバ定数を定義する
名前は慣習として型であればtype、値であればvalueを使う
Template Meta Programming入門

補足
コンパイル時にエラーチェックさせる
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; // 実装が無いのでコンパイルエラーになる
このような不正値に対して意図的にコンパイルエラーに出
来るようなコードを書く技法は良く使われる
Template Meta Programming入門

template<class T, std::size_t N, bool = (N > 0)>
比較演算子は括弧で囲む必要がある
std::vector<std::vector<int>>のようなネストされたテンプ
レートが>>演算子に解釈される問題はC++11以降では平気
Template Meta Programming入門

補足
static_assert
Template Meta Programming入門
コンパイル時アサート
static_assert(fact<6>::value == 720, "");
コンパイル時に計算可能な値に対して用いる
trueであれば無出力
falseであればコンパイルエラーになる
1番目の引数に条件式
2番目の引数にエラー時のメッセージを渡す
当然、実行時計算されるような値を渡すと失敗扱い
おしながき
1. Templateの基本確認
2. Template Meta Programmingとは
3. Template Meta Programming入門
4. Template Meta Programming応用
5. その他付録
6. まとめ
7. 質疑応答
Template Meta Programming応用

1. 関連知識をおさえる
2. 実践(有用なイディオムと例)
Template Meta Programming応用

これからTMPの応用に入る
その前に関連知識を知っておく
Template Meta Programming応用

・constexpr
・decltype
・SFINAE
Template Meta Programming応用

補足
constexpr
Template Meta Programming応用
C++11のconstexprに関して軽く説明する
私は陶芸家ではないので今回は深入りはしない
constexprに関して深く知りたい場合は
・中3女子でもわかる!constexpr
・中3女子が教える本当に気持ちのいい
 constexpr
・constexpr中3女子テクニック
などの有益な情報の載ったスライドがWeb上に公開されて
いるので各自Web上で検索して読むなどすると良い
Template Meta Programming応用
TMPにおける値の計算は整数しか扱えないと
いう弱点がある
(浮動小数点を無理矢理エミュレートしようとする人は居るが…)
(また、一応ratioのようなものもあるが…)

またコンパイル時にしか使えない
int a = 0;
add<a, 1>::value; // エラー、aは実行時オブジェクト
Template Meta Programming応用
C++03やconstexpr非対応のコンパイラの場
合はTMPを使うが、そうでない場合はただ
値を計算して、値を返すだけのようなメタ関
数はconstexpr関数で実装した方が好ましい
事も多いと思われる
Template Meta Programming応用
// コンパイル時に計算可能
template<class T>
constexpr T add(T x, T y)
{
return x + y;
}
見慣れた関数の形で実装出来る
実行時にも共通のインタフェースで使える
浮動小数点もOK
Template Meta Programming応用
次のような式はconstant expressionsと呼ばれる。(Constant
expressionはコンパイル時に評価され得る)
constant-expression:
conditional-expression
以降の条件部分はかなり細かいので、発表では適当に流す
ので各自確認しておいて欲しい
次ページ以降の条件に当てはまる場合、constexprにはなれ
ない
Template Meta Programming応用
条件
・this (非静的メンバ関数の本体に暗黙の変換の結果を含む、クラスメンバアク
セス式の後置式、として表れていない場合)
・リテラルクラスのconstexprコンストラクタとconstexpr関数以外の関数呼び出
し(オーバーロードの解決は普段通り適用される)
・constexpr関数やconstexprコンストラクタの定義の外での未定義動作の
constexpr関数や、未定義動作のconstexprコンストラクタの呼び出し
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ではない
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が定数でない
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
Template Meta Programming応用
条件
・非activeなunionのメンバやサブオブジェクトを参照するglvalueに適用される左
辺値から右辺値への変換
・constant expressionによって初期化されていない状態の値やデータメンバ参照
を参照するid-expression
・dynamic cast
・reinterpret_cast
・擬似destructorの呼び出し
・インクリメント及びデクリメント操作
・多態クラス型に対するtypeid式
・new式
・delete式
Template Meta Programming応用

条件
・ポインタ同士の減算
・結果が不特定な場所での比較に関連するような演算子(rational or equality
operator)
・代入及び複合代入
・throw式
Template Meta Programming応用

更に補足
実行時計算とコンパイル時計算の浮動小数点
演算の精度は異なる場合がある
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であるかは未定義である。
Template Meta Programming応用
・整数演算しか出来ないTMPに比べ
 constexprは浮動小数点演算もコンパイル
 時に出来る
・コンパイル時計算にしか使えないTMPに比
 べconstexprは実行時計算にも使える
・逆に型に関する処理はTMPでしか実現出
 来ない(TMPの独壇場)
Template Meta Programming応用

補足
decltype
Template Meta Programming応用

decltype
イメージとしてはsizeofの型バージョン
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.
Template Meta Programming応用
decltype
if e is an unparenthesized id-expression or an unparenthesized
class member access ...
要するにexpressionが括弧で囲まれていないような

decltype(expression)の形のものの場合
Template Meta Programming応用
例
char a;
decltype(a); // char
int b = 1;
int& c = b;
decltype(c); // int&
const int* d;
decltype(d); // const int*
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)
Template Meta Programming応用

例
void f(int);
void f(double);
decltype(f); // Error
関数に複数のオーバーロードがあるとダメ
Template Meta Programming応用
例
int f();
decltype(f()); // int
関数の戻り値の型も取れる
decltype(e)のeのexpressionが評価されることはないので関数
の定義は必要ない(TMPにおいて重要)
Template Meta Programming応用

decltype
decltype((expression))の形のものの場合
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なども含まれる)
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&になる
Template Meta Programming応用
decltype
otherwise, decltype(e) is the type of e.

それ以外(prvalue等)はeの型
例
decltype(1); // int
decltype("hello,world"); // const char[12]
Template Meta Programming応用

decltypeまとめ
・decltypeを使うとオブジェクトや関数の戻
 り値の型を得る事が出来る
・decltypeの結果は括弧の有無で変わる
Template Meta Programming応用

補足
SFINAE
Template Meta Programming応用

SFINAE
Substitution failure is not an error
Template Meta Programming応用

テンプレートの置き換えに失敗してもすぐ
にはエラーにならず他の候補を探す
必修知識だがC++入門書には多分載ってない
(結果として知らない人も居る印象)
Template Meta Programming応用

言葉より実例を見るほうが早い
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); 
}
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); 
}
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); 
}
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); 
}
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); 
}
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); 
}
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. 
}
Template Meta Programming応用

このようなルールをSFINAEと呼ぶ
条件分岐、エラーチェック等を実現出来る
(例は後述)
Template Meta Programming応用

1. 関連知識をおさえる
2. 実践(有用なイディオムと例)
Template Meta Programming応用

関連知識をおさえたところでいよいよ応用
として実用的なイディオム等を見ていく
Template Meta Programming応用
・Variadic templates 
 可変長引数テンプレートを扱う
・enable_if 
 SFINAEによる条件分岐
・index_tuple, index_range (index_sequence) 
 整数列パラメータパックの生成と利用
・Expression Template(ET)
 式テンプレート
Template Meta Programming応用

Variadic templates 
可変長引数テンプレートを扱う
Template Meta Programming応用
要素の追加
型リストを保持する単純なクラス
template<class... Types>
struct list
{
template<class Type>
struct push_back
{
using type = list<Types..., Type>; // これでOK
};
};
Template Meta Programming応用
要素の追加
例えばlist<int, char>::push_back<double>::typeのとき
Types...はint, charに展開され、Typeはdoubleであるから
list<Types..., Type>はlist<int, char, double>
Template Meta Programming応用
要素の追加
template<class... Types>
struct list
{
template<class Type>
struct push_front
{
using type = list<Type,Types...>; // これでOK
};
};
push_frontも同様に可能
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; };
};
Template Meta Programming応用
要素の削除
template<class Type, class... Types2>
struct pop_front_impl
{
using type = list<Types2...>;
};
複数受け取ったパラメータのうちの最初の1つだけTypeに入
り、残りは全てTypes2に入る
Template Meta Programming応用
要素の削除
pop_backだけは簡単にはいかない
実装も他の操作に比べ面倒、計算コストもかかる
template<class... Types2, class Type> // エラー、可変長引数テン
プレートはテンプレートパラメータのうち最後でなければ
ならない
再帰的な実装など工夫が必要
Template Meta Programming応用

enable_if 
SFINAEによる条件分岐
Template Meta Programming応用

enable_if
・SFINAEを利用した条件分岐を手助けする
 イディオム
・標準ライブラリにstd::enable_ifがある
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に利用出来る)
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つも見つからなければコンパイルエラー)
不正な型の引数が渡される事を防止出来る
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の対象は関数に限られたものではない
Template Meta Programming応用

もっとenable_if 
enabler idiom
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); // デフォルト引数が異なるだけの再定義はダメ
Template Meta Programming応用

type-parameterでのオーバーロードは厳しい
Template Meta Programming応用

そこで以下のような宣言を行う
extern void * enabler;
Template Meta Programming応用
extern void * enabler;
の定義は必要ない
enablerはextern修飾されているので外部リン
ケージを持つ
ということは
non-type template-parameter

non-type template-parameterに渡せるもの
外部リンケージのあるオブジェクト
・extern修飾されたもの
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);
Template Meta Programming応用
template<typename T, typename std::enable_if<
std::is_integral<T>::value>::type *& = enabler>
void f(T);
enable_ifを非型パラメータとして用いているのがポイント
(参照型は非型パラメータになれる)
enablerは外部リンケージを持つので非型パラメータに渡す
事が出来る
Template Meta Programming応用

わざわざ使わなくても十分なケースが多い
しかし、必要になることもある
Template Meta Programming応用

index_tuple, index_range (integer_sequence) 
整数列パラメータパックの生成と利用
Template Meta Programming応用
index_tuple idiomなどと呼ばれる
・整数列のパラメータパックを生成するイ
 ディオム
・C++14からはstd::integer_sequenceとして
 同様の機能が標準ライブラリ入り
・インデックスアクセス可能なデータ構造
 の効率の良い要素の走査、リスト内包表
 記相当の処理の実現
Template Meta Programming応用

・整数列パラメータを保持する型
・整数列パラメータを生成するヘルパメタ
 関数
のセットで用いられる
Template Meta Programming応用
例えばNを正の整数としたとき
index_range<0, N>::typeが
index_tuple<0,1,2,3, ..., N-1> 
と同じ型になるように実装する
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>>
{};
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>>
{};
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を保持
Template Meta Programming応用
index_rangeは整数列パラメータを生成する
ヘルパメタ関数
・結果を返す定義(デフォルト定義)
・整数列パラメータを生成するフローの為
 の部分特殊化
の2つの定義がある
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>>
{};
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;
};
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; // 型を定義して結果を返す
};
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>>
{};
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>>
{};
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>>
{};
Template Meta Programming応用

デフォルト定義における以下の部分
bool flag = first >= last // 再帰の終了条件
がfalseになったときだけ部分特殊化された定義が使われる
すなわち生成フローの定義が使われる
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>>
{};
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>>
{};
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を継承している
{};
Template Meta Programming応用
テンプレートパラメータ違いの自分自身を
継承すること
: index_range<step + 1, last, index_tuple<Indices..., step>> 

メタ関数における再帰を意味する
テンプレートパラメータは関数の引数相当
Template Meta Programming応用
: index_range<step + 1, last, index_tuple<Indices..., step>> 

この部分ではstepを1進め
可変長引数テンプレートパラメータの要素
にstepを追加して再帰する
index_tupleに渡す引数を増やしながら再帰している
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; // 結果型
};
Template Meta Programming応用

実用例
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}}が欲しい
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に推論される
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になる
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>である
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の引数
として渡される
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に推論される
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}}
という風に展開される
Template Meta Programming応用

基本的にインデックスアクセス可能なデー
タ構造であれば適用出来る
Template Meta Programming応用

余談
生成結果のメモ化
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)が期待出来る
Template Meta Programming応用

・メモリ使用量が増える可能性
・コンパイラの最適化によっては無意味 ・逆効果かも
同じ要素数で尚且つ数千要素のtuple展開を何度も行うよう
な場合には有効かもしれないが通常は使わなくて良さそう
Template Meta Programming応用

index_rangeの実装には簡単でクソなO(N)オーダーでの実装
の他に有用なO(log2(N))オーダーでの実装法も知られている
Template Meta Programming応用

線形オーダーでは扱える要素数が限られ、生成速度も遅い
のでSproutや標準ライブラリで後者の実装が使われている
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> 
が得られる
現実には実装はもっと面倒だが基本的には、このように前
の結果を利用して要素数を倍々にしていくという考え
Template Meta Programming応用

詳しい実装に関してはsprout::index_rangeなどを見て欲しい
Template Meta Programming応用

Expression Template(ET)
式テンプレート
Template Meta Programming応用

・式の評価を遅延させる
・余計な一時オブジェクトの生成とコピーの
 発生を防ぐ
Template Meta Programming応用

通常、巨大な行列の一時オブジェクトが生
成される演算に対して、演算の結果ではな
く演算を表す型オブジェクトを返す
Template Meta Programming応用
行列のA, B, Cの和
A+B+C
ETを使わない実装では、A + Bで値を計算し
て一時オブジェクトを生成、更に一時オブ
ジェクト + Cで値を計算して一時オブジェク
トを生成という事が起こりうる
その過程で巨大なオブジェクトのコピー、構
築が起こりうる
Template Meta Programming応用
行列のA, B, Cの和
Plus<Plus<Vector<A>,Vector<B>>,Vector<C>>
演算を型として表す、巨大な行列をコピーし
たりしなくて済むので、途中式の段階で一
時オブジェクトの生成コストが非常に小さ
くなる
Template Meta Programming応用

値はoperator=()が呼ばれた時に初めて評価さ
れる
Template Meta Programming応用
参考
ETの簡単な実装法やデメリット等も含めて
紹介されている
日本で一番分かりやすく書いたつもりの
Expression Templateの説明
http://d.hatena.ne.jp/Cryolite/20040506
などが分かりやすい
おしながき
1. Templateの基本確認
2. Template Meta Programmingとは
3. Template Meta Programming入門
4. Template Meta Programming応用
5. その他付録
6. まとめ
7. 質疑応答
その他付録

1. TMPとは直接関係ないイディオムなど
2. これからのTMPと関連イディオムなど
その他付録

型を受け取るユーザ定義リテラル
その他付録

整数リテラルと浮動小数点リテラルに限り
char...のテンプレート実引数として受け取る
ことが出来る
その他付録

template<char...>
void operator "" _to_string() {};
12345_to_string; // template<‘1’,’2’,’3’,’4’,’5’>として渡される
3.14_to_string; // template<‘3’,’.’,’1’,,4>
その他付録
#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同士の減算等にはもう少し気を配った方がいい感じがしますが)
その他付録

型文字列の生成に使える
ただし整数と浮動小数点のみ
ショージキ微妙だが今後に期待
その他付録

private namespace idiom 
detail等へのアクセスを制限する
その他付録
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(); // ルックアップに失敗しエラー
その他付録

無名名前空間が暗黙にusingされる事を逆手に取る
detailへのアクセスを殺せるので名前空間スコープで、メタ
関数の内部実装にどうしてもアクセスされたくない場合に
は有効
その他付録

1. TMPとは直接関係ないイディオムなど
2. これからのTMPと関連イディオムなど
その他付録
先程取り上げたinteger_sequenceの他にもあ
る、C++14(所謂N3690辺り) / C++1y以降に
入ると思われる機能とそれに関連する話
(大雑把に未来の話です)

ただしTMPに割と関連しそうなものだけ
その他付録

C++14以降で(ほぼ確実に)入る機能
その他付録

constexprの制限緩和
その他付録
・副作用、制御構文が使えるようになる
・ポインタ同士の減算が定数式になる
など
一部制限が増えている
・a conversion from type cv void * to a pointer-to-object type;
C++11ではreinterpret_castが禁止されていたのにvoid*の型
変換が禁止されていなかったが、これもダメに修正された
その他付録

ただし、constexpr関数では相変わらずエラーハンドリング
が困難なので

闊に副作用の濫用を行うと、例外安全性を

保つのが難しいので注意が必要
その他、細かい事は規格等を参照して欲しい
その他付録

decltype(auto)
その他付録

decltype(auto)は、式をdecltype()の中に書い
たのと同じ挙動になる
その他付録

江添さんの記事が分かりやすい
http://cpplover.blogspot.jp/2013/08/decltypeauto.html
その他付録
記事の例のみ引用する
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 &&
その他付録
関数の戻り値などに利用出来る
template < typename T, typename U >
auto g( T const & t, U const & u )
-> decltype( auto ) // decltype( f( t, u ) )と書かなくて済む
{
return f( t, u ) ;
}
その他付録

ジェネリックラムダ
その他付録

ラムダ式もテンプレート化出来る
auto NumElements = []<int N>(auto (&a)[N]) { return N; };
その他付録

Variable Templates 
変数テンプレート
その他付録

読んで字の如く、変数をテンプレート化する
その他付録
変数テンプレート
template<class T>
constexpr T pi = static_cast<T>(3.14);
pi<int> == 3;
pi<float> == 3.14;
異なる精度の値を得る
その他付録

変数テンプレート
template<class T1, T2>
constexpr bool is_same_v = std::is_same<T1, T2>::value;
is_same_v<int, double>; // false
面倒な::valueを書かずに済む
その他付録

C++1y(ここではC++14よりも後を意味する)
以降で入るかもしれない提案
その他付録

Concepts Lite 
軽量コンセプト
その他付録

C++11入りする予定だったConceptの軽量・改良版
幾つかペーパーのようなものが出ている模様
その他付録

プログラマにやさしい構文で型制約を行えるようになる
constexpr関数として型制約を定義する案など
使えるようになるのは当分先の話になりそうな気はします
その他付録

N3741
Opaque Alias
その他付録

Strong typedef 
ある型から別の型を作る
using identifier = access-specifier type-id opaque-definition
その他付録
using age = private int; // intとは別の型として認識される
// privateにより暗黙のキャストは許可しない
age age1 = static_cast<age>(20); // 明示的なキャストをする
age age2 = 18; // Error ageはintではない
これまでのtypedefやusingではこのような事は出来ない
その他付録

オーバーロード等も有効になる
int f(int);
age f(age);
別物として扱われる
その他付録

N3730
Specializations and namespaces
その他付録

ネストされた名前空間を閉じなくても特殊化を書けるよう
にする提案
その他付録
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 {
/* ... */
}
}
その他付録
namespace A {
namespace B {
/* ... */
class C {
/* ... */
};
template<>
struct ::std::hash<C> {
std::size_t operator()(C const &c) { /* ... */ }
};
/* ... */
}
}

このように書けるようになる
その他付録

N3728
Packaging Parameter Packs
その他付録

パラメータパックを保持するための型リストをサポートす
る提案
パラメータパックが間違いなく扱いやすくなる
具体例はN3728ペーパー参照
その他付録

N3413
Allowing arbitrary literal types for non-type
template parameters
その他付録

非型パラメータとして任意のリテラル型を許容しようとい
う提案
その他付録
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++の世界の法則が乱れる完全にヤバい提案
その他付録

N3761
Proposing type_at<>
その他付録

パラメータパックのN番目の要素にアクセス
する機能のメタ関数を標準に入れる提案
その他付録
簡単な実装案が書かれている
要するに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;
};
その他付録
簡単な実装案が書かれている
要するに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);
}
その他付録

対数オーダーで実装可能なのでAuthorに実装
の改良を提案する意見を送付した
その他付録

対数オーダーでの要素アクセスの実装
その他付録
次のようなメタ関数を用意する
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のように型列を対数オーダーで生成する
その他付録
次のようなメタ関数を用意する
template<class T>
struct type_wrapper
{
using type = T;
};
ただ型を保持するだけの型
その他付録
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を受け取る
その他付録
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に渡す
その他付録

type_wrapperの役割
・インスタンス化出来ない型も処理出来るようにする
その他付録
type_wrapperの役割
using type = typename decltype(impl(type_wrapper<T>()))::type;
例えばTが
template<class...> 
struct list; 
のようなインスタンス化不可能な型の場合
impl(list())はインスタンス化出来ずエラーになるが
impl(type_wrapper<T>())ならばインスタンス化出来て渡せる
その他付録

type_wrapperの役割
・トップレベルのcv修飾を保持する
その他付録

type_wrapperの役割
impl(type_wrapper<T>())ならば値渡しの際もArgument
Deductionにおいて、Tのcv修飾情報が失われずに済む
その他付録
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を使えばテンプレートクラスの
持つ型リストを抽出する事が出来る
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで
Template Meta Programming入門から応用まで

More Related Content

What's hot

C++の話(本当にあった怖い話)
C++の話(本当にあった怖い話)C++の話(本当にあった怖い話)
C++の話(本当にあった怖い話)Yuki Tamura
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装MITSUNARI Shigeo
 
Effective Modern C++ 勉強会#3 Item16
Effective Modern C++ 勉強会#3 Item16Effective Modern C++ 勉強会#3 Item16
Effective Modern C++ 勉強会#3 Item16Mitsuru Kariya
 
Gpgpu tomoaki-fp16
Gpgpu tomoaki-fp16Gpgpu tomoaki-fp16
Gpgpu tomoaki-fp16tomoaki0705
 
非同期処理の基礎
非同期処理の基礎非同期処理の基礎
非同期処理の基礎信之 岩永
 
いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門Fixstars Corporation
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろうKota Mizushima
 
GiNZAで始める日本語依存構造解析 〜CaboCha, UDPipe, Stanford NLPとの比較〜
GiNZAで始める日本語依存構造解析 〜CaboCha, UDPipe, Stanford NLPとの比較〜GiNZAで始める日本語依存構造解析 〜CaboCha, UDPipe, Stanford NLPとの比較〜
GiNZAで始める日本語依存構造解析 〜CaboCha, UDPipe, Stanford NLPとの比較〜Megagon Labs
 
君はyarn.lockをコミットしているか?
君はyarn.lockをコミットしているか?君はyarn.lockをコミットしているか?
君はyarn.lockをコミットしているか?Teppei Sato
 
LR parsing
LR parsingLR parsing
LR parsingichikaz3
 
Constexpr 中3女子テクニック
Constexpr 中3女子テクニックConstexpr 中3女子テクニック
Constexpr 中3女子テクニックGenya Murakami
 
日本語テストメソッドについて
日本語テストメソッドについて日本語テストメソッドについて
日本語テストメソッドについてkumake
 
マルチコアを用いた画像処理
マルチコアを用いた画像処理マルチコアを用いた画像処理
マルチコアを用いた画像処理Norishige Fukushima
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門Norishige Fukushima
 
MySQL勉強会 クエリチューニング編
MySQL勉強会 クエリチューニング編MySQL勉強会 クエリチューニング編
MySQL勉強会 クエリチューニング編MicroAd, Inc.(Engineer)
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 TipsTakaaki Suzuki
 
「ランダムフォレスト回帰」のハイパーパラメーター
「ランダムフォレスト回帰」のハイパーパラメーター「ランダムフォレスト回帰」のハイパーパラメーター
「ランダムフォレスト回帰」のハイパーパラメーターJun Umezawa
 
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetupこれで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線MeetupMasatoshi Tada
 

What's hot (20)

C++の話(本当にあった怖い話)
C++の話(本当にあった怖い話)C++の話(本当にあった怖い話)
C++の話(本当にあった怖い話)
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装
 
Effective Modern C++ 勉強会#3 Item16
Effective Modern C++ 勉強会#3 Item16Effective Modern C++ 勉強会#3 Item16
Effective Modern C++ 勉強会#3 Item16
 
プログラムを高速化する話
プログラムを高速化する話プログラムを高速化する話
プログラムを高速化する話
 
Gpgpu tomoaki-fp16
Gpgpu tomoaki-fp16Gpgpu tomoaki-fp16
Gpgpu tomoaki-fp16
 
非同期処理の基礎
非同期処理の基礎非同期処理の基礎
非同期処理の基礎
 
いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろう
 
Rcppのすすめ
RcppのすすめRcppのすすめ
Rcppのすすめ
 
GiNZAで始める日本語依存構造解析 〜CaboCha, UDPipe, Stanford NLPとの比較〜
GiNZAで始める日本語依存構造解析 〜CaboCha, UDPipe, Stanford NLPとの比較〜GiNZAで始める日本語依存構造解析 〜CaboCha, UDPipe, Stanford NLPとの比較〜
GiNZAで始める日本語依存構造解析 〜CaboCha, UDPipe, Stanford NLPとの比較〜
 
君はyarn.lockをコミットしているか?
君はyarn.lockをコミットしているか?君はyarn.lockをコミットしているか?
君はyarn.lockをコミットしているか?
 
LR parsing
LR parsingLR parsing
LR parsing
 
Constexpr 中3女子テクニック
Constexpr 中3女子テクニックConstexpr 中3女子テクニック
Constexpr 中3女子テクニック
 
日本語テストメソッドについて
日本語テストメソッドについて日本語テストメソッドについて
日本語テストメソッドについて
 
マルチコアを用いた画像処理
マルチコアを用いた画像処理マルチコアを用いた画像処理
マルチコアを用いた画像処理
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門
 
MySQL勉強会 クエリチューニング編
MySQL勉強会 クエリチューニング編MySQL勉強会 クエリチューニング編
MySQL勉強会 クエリチューニング編
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips
 
「ランダムフォレスト回帰」のハイパーパラメーター
「ランダムフォレスト回帰」のハイパーパラメーター「ランダムフォレスト回帰」のハイパーパラメーター
「ランダムフォレスト回帰」のハイパーパラメーター
 
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetupこれで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
 

Viewers also liked

闇魔術を触ってみた
闇魔術を触ってみた闇魔術を触ってみた
闇魔術を触ってみたSatoshi Sato
 
Boostのあるプログラミング生活
Boostのあるプログラミング生活Boostのあるプログラミング生活
Boostのあるプログラミング生活Akira Takahashi
 
C++入門?
C++入門?C++入門?
C++入門?tsudaa
 
Window 10 楽しい使い方
Window 10 楽しい使い方 Window 10 楽しい使い方
Window 10 楽しい使い方 Takae Sakushima
 
エクストリームC++11/14プログラミング
エクストリームC++11/14プログラミングエクストリームC++11/14プログラミング
エクストリームC++11/14プログラミングegtra
 
Windows 10 フォローアップ講座
Windows 10 フォローアップ講座Windows 10 フォローアップ講座
Windows 10 フォローアップ講座Takae Sakushima
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14Ryo Suzuki
 
ICLR読み会 奥村純 20170617
ICLR読み会 奥村純 20170617ICLR読み会 奥村純 20170617
ICLR読み会 奥村純 20170617Jun Okumura
 
[ICLR2017読み会 @ DeNA] ICLR2017紹介
[ICLR2017読み会 @ DeNA] ICLR2017紹介[ICLR2017読み会 @ DeNA] ICLR2017紹介
[ICLR2017読み会 @ DeNA] ICLR2017紹介Takeru Miyato
 
Semi-Supervised Classification with Graph Convolutional Networks @ICLR2017読み会
Semi-Supervised Classification with Graph Convolutional Networks @ICLR2017読み会Semi-Supervised Classification with Graph Convolutional Networks @ICLR2017読み会
Semi-Supervised Classification with Graph Convolutional Networks @ICLR2017読み会Eiji Sekiya
 
ICLR2017読み会 Data Noising as Smoothing in Neural Network Language Models @Dena
ICLR2017読み会 Data Noising as Smoothing in Neural Network Language Models @DenaICLR2017読み会 Data Noising as Smoothing in Neural Network Language Models @Dena
ICLR2017読み会 Data Noising as Smoothing in Neural Network Language Models @DenaTakanori Nakai
 
言葉のもつ広がりを、モデルの学習に活かそう -one-hot to distribution in language modeling-
言葉のもつ広がりを、モデルの学習に活かそう -one-hot to distribution in language modeling-言葉のもつ広がりを、モデルの学習に活かそう -one-hot to distribution in language modeling-
言葉のもつ広がりを、モデルの学習に活かそう -one-hot to distribution in language modeling-Takahiro Kubo
 

Viewers also liked (18)

闇魔術を触ってみた
闇魔術を触ってみた闇魔術を触ってみた
闇魔術を触ってみた
 
Boostのあるプログラミング生活
Boostのあるプログラミング生活Boostのあるプログラミング生活
Boostのあるプログラミング生活
 
C++ Presentation
C++ PresentationC++ Presentation
C++ Presentation
 
C++14 Overview
C++14 OverviewC++14 Overview
C++14 Overview
 
C++の黒魔術
C++の黒魔術C++の黒魔術
C++の黒魔術
 
C++入門?
C++入門?C++入門?
C++入門?
 
Window 10 楽しい使い方
Window 10 楽しい使い方 Window 10 楽しい使い方
Window 10 楽しい使い方
 
エクストリームC++11/14プログラミング
エクストリームC++11/14プログラミングエクストリームC++11/14プログラミング
エクストリームC++11/14プログラミング
 
Windows 10 フォローアップ講座
Windows 10 フォローアップ講座Windows 10 フォローアップ講座
Windows 10 フォローアップ講座
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14
 
ICLR読み会 奥村純 20170617
ICLR読み会 奥村純 20170617ICLR読み会 奥村純 20170617
ICLR読み会 奥村純 20170617
 
[ICLR2017読み会 @ DeNA] ICLR2017紹介
[ICLR2017読み会 @ DeNA] ICLR2017紹介[ICLR2017読み会 @ DeNA] ICLR2017紹介
[ICLR2017読み会 @ DeNA] ICLR2017紹介
 
Semi-Supervised Classification with Graph Convolutional Networks @ICLR2017読み会
Semi-Supervised Classification with Graph Convolutional Networks @ICLR2017読み会Semi-Supervised Classification with Graph Convolutional Networks @ICLR2017読み会
Semi-Supervised Classification with Graph Convolutional Networks @ICLR2017読み会
 
ICLR2017読み会 Data Noising as Smoothing in Neural Network Language Models @Dena
ICLR2017読み会 Data Noising as Smoothing in Neural Network Language Models @DenaICLR2017読み会 Data Noising as Smoothing in Neural Network Language Models @Dena
ICLR2017読み会 Data Noising as Smoothing in Neural Network Language Models @Dena
 
言葉のもつ広がりを、モデルの学習に活かそう -one-hot to distribution in language modeling-
言葉のもつ広がりを、モデルの学習に活かそう -one-hot to distribution in language modeling-言葉のもつ広がりを、モデルの学習に活かそう -one-hot to distribution in language modeling-
言葉のもつ広がりを、モデルの学習に活かそう -one-hot to distribution in language modeling-
 
医療データ解析界隈から見たICLR2017
医療データ解析界隈から見たICLR2017医療データ解析界隈から見たICLR2017
医療データ解析界隈から見たICLR2017
 
170614 iclr reading-public
170614 iclr reading-public170614 iclr reading-public
170614 iclr reading-public
 
Q prop
Q propQ prop
Q prop
 

Similar to Template Meta Programming入門から応用まで

Yapc::Asia 2011 rejectConf Slide
Yapc::Asia 2011 rejectConf SlideYapc::Asia 2011 rejectConf Slide
Yapc::Asia 2011 rejectConf SlideSeiji Ohira
 
MTDDC Hokkaido : テンプレートタグでBrainf*ckを作ってみた
MTDDC Hokkaido : テンプレートタグでBrainf*ckを作ってみたMTDDC Hokkaido : テンプレートタグでBrainf*ckを作ってみた
MTDDC Hokkaido : テンプレートタグでBrainf*ckを作ってみたKatsuhiro Endo
 
C++勉強会in広島プレゼン資料
C++勉強会in広島プレゼン資料C++勉強会in広島プレゼン資料
C++勉強会in広島プレゼン資料真一 北原
 
君はまだ,本当のプリプロセスを知らない
君はまだ,本当のプリプロセスを知らない君はまだ,本当のプリプロセスを知らない
君はまだ,本当のプリプロセスを知らないdigitalghost
 
カラーミーショップ「カスタマイズスクール第1期vol.1」
カラーミーショップ「カスタマイズスクール第1期vol.1」カラーミーショップ「カスタマイズスクール第1期vol.1」
カラーミーショップ「カスタマイズスクール第1期vol.1」ec-campus
 
C++ Template Metaprogramming
C++ Template MetaprogrammingC++ Template Metaprogramming
C++ Template MetaprogrammingAkira Takahashi
 
Python と型ヒント (Type Hints)
Python と型ヒント (Type Hints)Python と型ヒント (Type Hints)
Python と型ヒント (Type Hints)Tetsuya Morimoto
 
Pythonと型チェッカー
Pythonと型チェッカーPythonと型チェッカー
Pythonと型チェッカーTetsuya Morimoto
 
.NET micro FrameWork for TOPPERS (.NET基礎)@基礎勉強会
.NET micro  FrameWork for TOPPERS  (.NET基礎)@基礎勉強会.NET micro  FrameWork for TOPPERS  (.NET基礎)@基礎勉強会
.NET micro FrameWork for TOPPERS (.NET基礎)@基礎勉強会Kiyoshi Ogawa
 
Chainerの使い方と自然言語処理への応用
Chainerの使い方と自然言語処理への応用Chainerの使い方と自然言語処理への応用
Chainerの使い方と自然言語処理への応用Seiya Tokui
 
C++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるHideyuki Tanaka
 
DTrace for biginners part(2)
DTrace for biginners part(2)DTrace for biginners part(2)
DTrace for biginners part(2)Shoji Haraguchi
 
DATUM STUDIO PyCon2016 Turorial
DATUM STUDIO PyCon2016 TurorialDATUM STUDIO PyCon2016 Turorial
DATUM STUDIO PyCon2016 TurorialTatsuya Tojima
 
続・わかりやすいパターン認識 第7章「マルコフモデル」
続・わかりやすいパターン認識 第7章「マルコフモデル」続・わかりやすいパターン認識 第7章「マルコフモデル」
続・わかりやすいパターン認識 第7章「マルコフモデル」T T
 

Similar to Template Meta Programming入門から応用まで (20)

Yapc::Asia 2011 rejectConf Slide
Yapc::Asia 2011 rejectConf SlideYapc::Asia 2011 rejectConf Slide
Yapc::Asia 2011 rejectConf Slide
 
What is template
What is templateWhat is template
What is template
 
MTDDC Hokkaido : テンプレートタグでBrainf*ckを作ってみた
MTDDC Hokkaido : テンプレートタグでBrainf*ckを作ってみたMTDDC Hokkaido : テンプレートタグでBrainf*ckを作ってみた
MTDDC Hokkaido : テンプレートタグでBrainf*ckを作ってみた
 
C++勉強会in広島プレゼン資料
C++勉強会in広島プレゼン資料C++勉強会in広島プレゼン資料
C++勉強会in広島プレゼン資料
 
君はまだ,本当のプリプロセスを知らない
君はまだ,本当のプリプロセスを知らない君はまだ,本当のプリプロセスを知らない
君はまだ,本当のプリプロセスを知らない
 
カラーミーショップ「カスタマイズスクール第1期vol.1」
カラーミーショップ「カスタマイズスクール第1期vol.1」カラーミーショップ「カスタマイズスクール第1期vol.1」
カラーミーショップ「カスタマイズスクール第1期vol.1」
 
C++ Template Metaprogramming
C++ Template MetaprogrammingC++ Template Metaprogramming
C++ Template Metaprogramming
 
Python と型ヒント (Type Hints)
Python と型ヒント (Type Hints)Python と型ヒント (Type Hints)
Python と型ヒント (Type Hints)
 
Pythonと型チェッカー
Pythonと型チェッカーPythonと型チェッカー
Pythonと型チェッカー
 
C++0x concept
C++0x conceptC++0x concept
C++0x concept
 
.NET micro FrameWork for TOPPERS (.NET基礎)@基礎勉強会
.NET micro  FrameWork for TOPPERS  (.NET基礎)@基礎勉強会.NET micro  FrameWork for TOPPERS  (.NET基礎)@基礎勉強会
.NET micro FrameWork for TOPPERS (.NET基礎)@基礎勉強会
 
Chainerの使い方と自然言語処理への応用
Chainerの使い方と自然言語処理への応用Chainerの使い方と自然言語処理への応用
Chainerの使い方と自然言語処理への応用
 
C++の復習
C++の復習C++の復習
C++の復習
 
CMSI計算科学技術特論A (2015) 第3回 OpenMPの基礎
CMSI計算科学技術特論A (2015) 第3回 OpenMPの基礎CMSI計算科学技術特論A (2015) 第3回 OpenMPの基礎
CMSI計算科学技術特論A (2015) 第3回 OpenMPの基礎
 
N3701 concept lite
N3701 concept liteN3701 concept lite
N3701 concept lite
 
C++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISる
 
Frequency with nltk
Frequency with nltkFrequency with nltk
Frequency with nltk
 
DTrace for biginners part(2)
DTrace for biginners part(2)DTrace for biginners part(2)
DTrace for biginners part(2)
 
DATUM STUDIO PyCon2016 Turorial
DATUM STUDIO PyCon2016 TurorialDATUM STUDIO PyCon2016 Turorial
DATUM STUDIO PyCon2016 Turorial
 
続・わかりやすいパターン認識 第7章「マルコフモデル」
続・わかりやすいパターン認識 第7章「マルコフモデル」続・わかりやすいパターン認識 第7章「マルコフモデル」
続・わかりやすいパターン認識 第7章「マルコフモデル」
 

Template Meta Programming入門から応用まで