More Related Content Similar to Template Meta Programming入門から応用まで Similar to Template Meta Programming入門から応用まで (20) Template Meta Programming入門から応用まで2. 自己紹介
twitter : @fimbul11
github : fimbul
University of Tsukuba B3
専攻 : 情報とメディア技術(mast)
プログラミングとかやってます、歴は2年ちょっとぐらいです
C++とかやってます、歴は1年半ぐらいです
ペン回しとか出来ます、歴は7年ぐらいです
20. Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
21. Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
24. Template is 何
14 Templates
A template defines a family of classes or
functions or an alias for a family of types.
27. Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
36. Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
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. 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の後の要素は省略可能
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
72. Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
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>は渡した型を扱える
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に
ある値が入った状態のものは特殊化されているといえる
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. Class templates
template<class T1, class T2, int I> class A {}; // unspecialized
template<class T, int I> class A<T, T*, I> {};
このように抽象的なテンプレートパラメータの数を減らし
部分的に具体的要素に置き換えた特殊化を作る事が出来る
85. Class templates
template<class T1, class T2, int I> class A {}; // unspecialized
template<class T, int I> class A<T, T*, I> {};
部分特殊化されたテンプレートは、条件を満たす場合には
特殊化されていないテンプレートより優先的にマッチする
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において非常に重要
93. Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
116. Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
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. 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.
123. Alias templates
Template Meta Programmingではtypenameと
か::typeを書かなくて済むようにする為に
使ったりする
template<class T>
using add_p = typename std::add_pointer<T>::type;
add_p<int>; // int*
131. Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
132. Variadic templates
1. A template parameter pack is a template
parameter that accepts zero or more template
arguments.
133. Variadic templates
2. A function parameter pack is a function
parameter that accepts zero or more function
arguments.
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の後の要素は省略可能
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. 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
に推論される
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&);
と等価になっている
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. 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. 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}になる
161. Templateの基本確認
目次
1. Template is 何
2. テンプレートの文法
2-1. テンプレートパラメータ
2-2. クラステンプレート
2-3. 関数テンプレート
2-4. エイリアステンプレート
2-5. 可変長引数テンプレート
2-6. template template parameter
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の後の要素は省略可能
166. Template Template Parameters
template < template-parameter-list > class ...opt identifieropt
template < template-parameter-list > class identifieropt= idexpression
このようにして受け取れる
optにellipsisがあるように可変長引数でも可能
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;
};
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を利用するこ
とで再帰を実現する
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をインスタンス化する)
219. Template Meta Programming応用
// コンパイル時に計算可能
template<class T>
constexpr T add(T x, T y)
{
return x + y;
}
見慣れた関数の形で実装出来る
実行時にも共通のインタフェースで使える
浮動小数点もOK
220. Template Meta Programming応用
次のような式はconstant expressionsと呼ばれる。(Constant
expressionはコンパイル時に評価され得る)
constant-expression:
conditional-expression
以降の条件部分はかなり細かいので、発表では適当に流す
ので各自確認しておいて欲しい
次ページ以降の条件に当てはまる場合、constexprにはなれ
ない
221. Template Meta Programming応用
条件
・this (非静的メンバ関数の本体に暗黙の変換の結果を含む、クラスメンバアク
セス式の後置式、として表れていない場合)
・リテラルクラスのconstexprコンストラクタとconstexpr関数以外の関数呼び出
し(オーバーロードの解決は普段通り適用される)
・constexpr関数やconstexprコンストラクタの定義の外での未定義動作の
constexpr関数や、未定義動作のconstexprコンストラクタの呼び出し
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. 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が定数でない
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.
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なども含まれる)
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. 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. 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. 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. 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. 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. 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.
}
257. Template Meta Programming応用
・Variadic templates
可変長引数テンプレートを扱う
・enable_if
SFINAEによる条件分岐
・index_tuple, index_range (index_sequence)
整数列パラメータパックの生成と利用
・Expression Template(ET)
式テンプレート
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; };
};
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. 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の対象は関数に限られたものではない
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. 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. 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を保持
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>>
{};
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>>
{};
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>>
{};
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. 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. 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を継承している
{};
298. Template Meta Programming応用
: index_range<step + 1, last, index_tuple<Indices..., step>>
この部分ではstepを1進め
可変長引数テンプレートパラメータの要素
にstepを追加して再帰する
index_tupleに渡す引数を増やしながら再帰している
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. 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. 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. 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. 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. 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. 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}}
という風に展開される
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)が期待出来る
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>
が得られる
現実には実装はもっと面倒だが基本的には、このように前
の結果を利用して要素数を倍々にしていくという考え
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同士の減算等にはもう少し気を配った方がいい感じがしますが)
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(); // ルックアップに失敗しエラー
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 &&
356. その他付録
using age = private int; // intとは別の型として認識される
// privateにより暗黙のキャストは許可しない
age age1 = static_cast<age>(20); // 明示的なキャストをする
age age2 = 18; // Error ageはintではない
これまでのtypedefやusingではこのような事は出来ない
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. その他付録
namespace A {
namespace B {
/* ... */
class C {
/* ... */
};
template<>
struct ::std::hash<C> {
std::size_t operator()(C const &c) { /* ... */ }
};
/* ... */
}
}
このように書けるようになる
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++の世界の法則が乱れる完全にヤバい提案
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. その他付録
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に渡す
378. その他付録
type_wrapperの役割
using type = typename decltype(impl(type_wrapper<T>()))::type;
例えばTが
template<class...>
struct list;
のようなインスタンス化不可能な型の場合
impl(list())はインスタンス化出来ずエラーになるが
impl(type_wrapper<T>())ならばインスタンス化出来て渡せる
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を使えばテンプレートクラスの
持つ型リストを抽出する事が出来る