Contenu connexe
Similaire à リテラル文字列型までの道 (20)
リテラル文字列型までの道
- 7. やること一覧
• 前回の復習+必要なC++の仕様の確認
• C++的メタプログラミングとは
• ライブラリの仕様を考えよう
• 汎用的メタ関数を作ろう(type_traits.hpp)
• 強化型index_tupleとは(index_tuple.hpp)
• 配列のラッパーを作る(array.hpp)
• 配列の操作をしよう(array_algorithm.hpp)
• 文字列型を作ろう(basic_string.hpp)
• そしてコンパイル時文字列操作へ…(string_control.hpp)
• 参考資料とまとめ
- 8. やること一覧
• 前回の復習+必要なC++の仕様の確認
• C++的メタプログラミングとは
• ライブラリの仕様を考えよう
• 汎用的メタ関数を作ろう(type_traits.hpp)
• 強化型index_tupleとは(index_tuple.hpp)
• 配列のラッパーを作る(array.hpp)
• 配列の操作をしよう(array_algorithm.hpp)
• 文字列型を作ろう(basic_string.hpp)
• そしてコンパイル時文字列操作へ…(string_control.hpp)
• 参考資料とまとめ
- 10. constexprの確認
• コンパイル時定数作ったり定数式作ったりするキーワード
• 定数式の実装は実質return文一つ
• classが条件を満たせばリテラル型と扱われconstexprで使える
• 別の非volatileなリテラル型のみをメンバ変数に持ち、「aggregateである」か
「1つ以上のムーブでもコピーでもないconstexprコンストラクタと
トリビアルなデストラクタ(要はユーザー定義されてない)を持つ」
• intなどの基本データ型はリテラル型、要はこれらから再帰的に定義される
• aggregateの条件は後に載せる
• templateなconstexpr宣言された関数について、constexpr関数の
制約に合わないインスタンス化された場合ill-formedにはならないが
普通の関数として扱われる
• constexprメンバ関数は暗黙でconst修飾される(後に問題になる)
- 19. 展開の仕方にも色々ある
• 例えばtemplate<size_t… Nums>があるとして0,1,2,3を渡したとする
• size_t x[]={ Nums… }でsize_t x[]={ 0 , 1 , 2 , 3 } に展開される
• size_t y[]={ x[Nums]… }でsize_t y[]={ x[0] , x[1] , x[2] , x[3] }に
• size_t z[]={ (4 + Nums)… }でsize_t z[]={ 4 , 5 , 6 , 7 }に展開される
• size_t w[]={ func( Nums )… }で
size_t w[]={ func(0), func(1), func(2), func(3) }
- 22. その他雑多なこと
using エイリアス
• using hoge = piyo;でhogeがpiyoと同じになる
• templateも可能(template<int N>using hoge = piyo<N>;など)
static_assert
• コンパイル時整数定数と文字列リテラルを渡して使う
• 整数定数がfalseなら文字列を出力してコンパイルエラーになる
typename
• templateをほげほげするコードだと型であるか分からない時がある
• これをつけておくと「型である」とコンパイラに伝えられる
- 23. やること一覧
• 前回の復習+必要なC++の仕様の確認
• C++的メタプログラミングとは
• ライブラリの仕様を考えよう
• 汎用的メタ関数を作ろう(type_traits.hpp)
• 強化型index_tupleとは(index_tuple.hpp)
• 配列のラッパーを作る(array.hpp)
• 配列の操作をしよう(array_algorithm.hpp)
• 文字列型を作ろう(basic_string.hpp)
• そしてコンパイル時文字列操作へ…(string_control.hpp)
• 参考資料とまとめ
- 28. やること一覧
• 前回の復習+必要なC++の仕様の確認
• C++的メタプログラミングとは
• ライブラリの仕様を考えよう
• 汎用的メタ関数を作ろう(type_traits.hpp)
• 強化型index_tupleとは(index_tuple.hpp)
• 配列のラッパーを作る(array.hpp)
• 配列の操作をしよう(array_algorithm.hpp)
• 文字列型を作ろう(basic_string.hpp)
• そしてコンパイル時文字列操作へ…(string_control.hpp)
• 参考資料とまとめ
- 32. やること一覧
• 前回の復習+必要なC++の仕様の確認
• C++的メタプログラミングとは
• ライブラリの仕様を考えよう
• 汎用的メタ関数を作ろう(type_traits.hpp)
• 強化型index_tupleとは(index_tuple.hpp)
• 配列のラッパーを作る(array.hpp)
• 配列の操作をしよう(array_algorithm.hpp)
• 文字列型を作ろう(basic_string.hpp)
• そしてコンパイル時文字列操作へ…(string_control.hpp)
• 参考資料とまとめ
- 37. enable_if
• どうやって使うの
• 例えばこんな使い方がある
template<size_t N>typename enable_if<(N%2==0),bool>::type
hoge(){return true;}
template<size_t N>typename enable_if<!(N%2==0),bool>::type
hoge(){return false;}
• enable_ifを使うのにtypenameがいるのは第1引数の値によってそも
そもtypeが存在しない場合があるため
• Nが奇数なら上はtypeが存在しないので置き換え失敗
• Nが偶数なら下はtypeが存在しないので置き換え失敗
• これで条件によって実装分岐が出来た
- 39. やること一覧
• 前回の復習+必要なC++の仕様の確認
• C++的メタプログラミングとは
• ライブラリの仕様を考えよう
• 汎用的メタ関数を作ろう(type_traits.hpp)
• 強化型index_tupleとは(index_tuple.hpp)
• 配列のラッパーを作る(array.hpp)
• 配列の操作をしよう(array_algorithm.hpp)
• 文字列型を作ろう(basic_string.hpp)
• そしてコンパイル時文字列操作へ…(string_control.hpp)
• 参考資料とまとめ
- 41. index_tuple
• とりあえずtemplate<int… Nums>struct index_tuple;を定義する
• テンプレート引数でclassを取るようにテンプレートクラスを定義、
index_tuple<Nums…>で特殊化しその時渡したいクラスの
テンプレート引数にNums…を渡してホゲホゲする
• 何らかのクラスがメンバにusing type = index_tuple<Nums…>を持つ
ようにして先ほどのクラスにtypeを渡せば目的が達成される
- 44. 準備
• 前の結果のindex_tupleを次の最大値をもらってそこから次の
index_tupleを返すメタ関数を作る
template<class Index,int N,bool is_odd>struct index_count_next;
template<int… Nums,int End>
struct index_count_next<index_tuple<Nums…>,End,true>
{using type = index_tuple<Nums…,(End+Nums)…>;};
Template<int… Nums,int End>
struct index_count_next<index_tuple<Nums…>,End,false>
{using type = index_tuple<Nums…,(End+Nums)…,2*End>;};
template<>struct index_count_next<index_tuple<>,0,false>
{using type = index_tuple<0>;};
• 0に繋がるのは1のみであるためこのように特殊化して問題はない
- 46. 要はこう
constexpr int get_next(int N){return (N%2 == 0 ? N/2 : (N-1)/2);}
template<int N>struct index_count{
using type = index_count_next<
index_count< get_next(N) >::type ,
get_next(N) ,
N%2==0)>::type;
};
template<>struct index_count<0>{
using type = index_tuple<>;
};
- 48. じゃあどうするの
• こんな感じでいいっしょ
template<class,int,int>struct index_range_impl;
template<int… Nums,int Step,int Start>struct
index_range_impl<index_tuple<Nums…>,Step,Start>
{using type = index_tuple<(Start*Nums+Step)…>;};
template<int Start,int End,int Step>
using index_range = index_range_impl<typename
index_count< 1 + (End-Start)/Step >::type , Step , Start>;
• enable_if使ってEnd-Start/Step<0の時index_tuple<>を
typeにするのもアリ
- 49. やること一覧
• 前回の復習+必要なC++の仕様の確認
• C++的メタプログラミングとは
• ライブラリの仕様を考えよう
• 汎用的メタ関数を作ろう(type_traits.hpp)
• 強化型index_tupleとは(index_tuple.hpp)
• 配列のラッパーを作る(array.hpp)
• 配列の操作をしよう(array_algorithm.hpp)
• 文字列型を作ろう(basic_string.hpp)
• そしてコンパイル時文字列操作へ…(string_control.hpp)
• 参考資料とまとめ
- 58. 実装
template<class,class,size_t>struct array_lap_impl;
template<int… Nums,class Ty,size_t SIZE>
struct array_lap_impl<index_tuple<Nums…>,Ty,SIZE>{
static constexpr array<Ty,SIZE> get(const Ty (&ar)[SIZE])
{ return array<Ty,SIZE>{ar[Nums]…}; } };
template<class Ty,size_t SIZE>
constexpr array<Ty,SIZE> array_lap(const Ty (&ar)[SIZE])
{return array_lap_impl<typename
index_count<SIZE>::type,Ty,SIZE>::get(ar); }
- 59. やること一覧
• 前回の復習+必要なC++の仕様の確認
• C++的メタプログラミングとは
• ライブラリの仕様を考えよう
• 汎用的メタ関数を作ろう(type_traits.hpp)
• 強化型index_tupleとは(index_tuple.hpp)
• 配列のラッパーを作る(array.hpp)
• 配列の操作をしよう(array_algorithm.hpp)
• 文字列型を作ろう(basic_string.hpp)
• そしてコンパイル時文字列操作へ…(string_control.hpp)
• 参考資料とまとめ
- 63. index_rangeを使おう
template<class>struct array_replace;
template<int… Nums>struct array_replace {
template<class Ty,size_t ArgSIZE,size_t RetSIZE>
static constexpr array<Ty,RetSIZE>
get(const array<Ty,ArgSIZE>& ar)
{return array<Ty,ReSIZE>{ar[Nums]…};}};
template<size_t Start,size_t End,class Ty,size_t SIZE>
constexpr array<Ty,End-Start+1>array_cut(const array<Ty,SIZE>& ar)
{return array_replace<typename
index_range<Start,End>::type>::get<Ty,ArgSIZE,RetSIZE>(ar);}
• Start番目からEnd番目の要素を抜き出す関数
- 65. 2つのarrayと2つのindex_count
template<class,class>struct array_merge_impl;
template<int… NumsA,int… NumsB>struct array_merge_impl
<index_tuple<NumsA…>,index_tuple<NumsB…>>{
template<class TyA,size_t SIZEA,class TyB,size_t SIZEB>
static constexpr array<TyA,SIZEA+SIZEB>
get(const array<TyA,SIZEA>& arA,const array<TyB,SIZEB>& arB)
{return array<TyA,SIZEA+SIZEB>
{arA[NumsA]…,static_cast<TyA>(arB[NumsB])…};}};
template<class TyA,size_t SIZEA,class TyB,size_t SIZEB>
constexpr array<TyA,SIZEA+SIZEB>
array_merge(const array<TyA,SIZEA>& arA,const array<TyB,SIZEB>& arB)
{return array_merge_impl
<typename index_count<SIZEA>::type, typename index_count<SIZEB>::type>
::get(arA,arB);}
• 一つのスライドに収めるもんじゃねぇ
- 67. for_eachの実装
template<class>struct for_each_impl;
template<size_t Nums…>class for_each_impl<index_tuple<Nums…>>{
template<class RetTy,class ArgTy,size_t SIZE,class FuncTy>
constexpr array<RetTy,SIZE>
get(const array<ArgTy,SIZE>& ar,FuncTy& func)
{return array<RetTy,SIZE>{ func(ar[Nums])… };} };
template<class RetTy,class ArgTy,size_t SIZE,class FuncTy>
constexpr array<RetTy,SIZE>
for_each(const array<RetTy,SIZE> &ar,FuncTy& func)
{return for_each_impl<typename index_count<SIZE>::type>
::get<RetTy>(ar,func);}
• 実行時に要素を直接いじるfor_eachも考えたかったけど面倒だった
• decltype使えばいいことに気づいたのは上のコード書いた後だった
- 69. こんな感じ
template<class Ty,size_t Num,class FuncTy>
constexpr size_t match_num
(array<Ty,Num>& ar,FuncTy& func,size_t start=0,size_t end=Num-1)
{return (start==end ? static_cast<bool>(func(ar[start])) :
match_num(ar,func,start,(start+end)/2) +
match_num(ar,func,(start+end)/2+1,end));}
• startからendまでチェック
• 分割地点については→
- 70. やること一覧
• 前回の復習+必要なC++の仕様の確認
• C++的メタプログラミングとは
• ライブラリの仕様を考えよう
• 汎用的メタ関数を作ろう(type_traits.hpp)
• 強化型index_tupleとは(index_tuple.hpp)
• 配列のラッパーを作る(array.hpp)
• 配列の操作をしよう(array_algorithm.hpp)
• 文字列型を作ろう(basic_string.hpp)
• そしてコンパイル時文字列操作へ…(string_control.hpp)
• 参考資料とまとめ
- 74. 文字列を結合する
• 2つの文字列を結合させたい
• 文字列aとbをa+bで結合させる
• aの末端はnull文字なのでそれは無視する
• するとこう
template<class T,size_t SA,size_t SB>basic_string<T,SA+SB-1>
operator+(const basic_string<T,SA>& a,const basic_string<T,SB>& b)
{return basic_string<T,SA+SB-1>(array_merge(array_cut<0,SA-2>(a.str_),b.str_));}
- 77. 実装
template<class Ty>constexpr Ty get_digit_num(int num,int digit)
{return static_cast<Ty>(static_cast<int>(’0’) +
( (num /pow(10,digit) )%10));
template<class,class,size_t>struct to_string_impl;
template<int… Nums,class Ty,size_t SIZE>
struct to_string_impl<index_tuple<Nums…>,Ty,SIZE>{
static constexpr array<Ty,SIZE> get(const int& num)
{return array<Ty,SIZE>{get_digit_num(num,SIZE-Nums-1)…};}};
• pow(int,int)はmath.hppあたりにでも定義しときましょう
• ‘0’の文字コードを知らなくてもできる実装(速度とか知らん)
- 79. 実装
template<class Ty,size_t SIZE>constexpr bool string_equal_impl
(const array<Ty,SIZE>& a,const array<Ty,SIZE>& b,
size_t start=0,size_t end=SIZE-1){
return ( start==end ? a[start]==b[start] :
string_equal_impl(a,b,start,(start+end)/2))&&
string_equal_impl(a,b,(start+end)/2+1),end);}
template<class TyA,size_t SA,class TyB,size_t SB>constexpr typename
enable_if<(SA==SB)&&(is_same<TyA,TyB>::value),bool>::type
operator==(const basic_string<TyA,SA>& a,
const basic_string<TyB,SB>&b){return string_equal_impl(a,b);}
template<class TyA,size_t SA,class TyB,size_t SB> constexpr typename
enable_if<!((SA==SB)&&(is_same<TyA,TyB>::value)),bool>::type
operator==(const basic_string<TyA,SA>& a,
const basic_string<TyB,SB>&b){return false;}
• 長い、長すぎる
• なおis_sameの出番ここで終了の模様
- 80. やること一覧
• 前回の復習+必要なC++の仕様の確認
• C++的メタプログラミングとは
• ライブラリの仕様を考えよう
• 汎用的メタ関数を作ろう(type_traits.hpp)
• 強化型index_tupleとは(index_tuple.hpp)
• 配列のラッパーを作る(array.hpp)
• 配列の操作をしよう(array_algorithm.hpp)
• 文字列型を作ろう(basic_string.hpp)
• そしてコンパイル時文字列操作へ…(string_control.hpp)
• 参考資料とまとめ
- 92. 途中結果を引数として渡す工夫
• Is_numとget_numはそれぞれ数字のチェックと数字のゲット
constexpr int string_to_integer(string str,int ret,size_t start,size_t end)
{return start==end ?
(is_num(str.str_[start]) ? 10*ret + get_num(str.str_[start]) : ret)
: string_to_integer(
str , string_to_integer
(str , ret , start , (start+end)/2 ),
(start+end)/2+1,end) );}
- 93. 他にも作ろうとしたもの
• 文字列逆転
• abcdをdcbaにするみたいな
• index_rangeとarray_replaceとarray_mergeを使ってほげほげ
• 文字列切り取り
• DtYaZsKからYaZsを取り出したいとか
• ポインタとindex_countで揃える
• 文字列一部抹消
• 上の逆でDtYaZsKからDtKを取り出すみたいな
• index_countとindex_rangeを組み合わせて云々
• 置換関数にnull文字だけの配列渡したほうが早い気もする
- 94. やること一覧
• 前回の復習+必要なC++の仕様の確認
• C++的メタプログラミングとは
• ライブラリの仕様を考えよう
• 汎用的メタ関数を作ろう(type_traits.hpp)
• 強化型index_tupleとは(index_tuple.hpp)
• 配列のラッパーを作る(array.hpp)
• 配列の操作をしよう(array_algorithm.hpp)
• 文字列型を作ろう(basic_string.hpp)
• そしてコンパイル時文字列操作へ…(string_control.hpp)
• 参考資料とまとめ
- 95. constexprまとめ
• 線形探索は範囲分割法を使えば再帰深度を対数オーダーにできる
• 分割範囲はstart to (start+end)/2と(start+end)/2+1 to end
• +で繋げる、&&で繋げる、前半を後半の引数に渡す、など
• templateと例外はうまく使おう
• 特にenable_ifは便利(classの特殊化より色々楽)
• 標準ライブラリのtype_traitsは要注目
• わざわざ苦しんでやるものでもないです
• 素直にclang3.4以降使った方がいい
• C++14のconstexprは手続き型の書き方でいける
- 97. 参考資料(スライド編)
• ボレロ村上氏のスライド
• 中3女子でもわかる constexpr
http://www.slideshare.net/GenyaMurakami/constexpr-10458089
• 中3女子が狂える本当に気持ちのいい constexpr
http://www.slideshare.net/GenyaMurakami/constexpr-11509325
• constexpr中3女子テクニック
http://www.slideshare.net/GenyaMurakami/constexpr-23355469
• すごいconstexprたのしくレイトレ!
http://www.slideshare.net/GenyaMurakami/constexpr-29223898
• 蔵人紗音のじ氏のスライド
• Template Meta Programming入門から応用まで
https://dl.dropboxusercontent.com/u/43530447/tmp_web.pdf
- 98. 参考資料(サイトや文献編)
• ENiyGmaA Code http://d.hatena.ne.jp/boleros/
• index_tuple イディオムにおける index_range の効率的な実装
http://d.hatena.ne.jp/boleros/20120406/1333682532
• Wonderlands in Usagi's brain http://blog.wonderrabbitproject.net/
• C++におけるtemplateキーワードの効果の忘却とついでにtypenameについて
http://blog.wonderrabbitproject.net/2013/02/ctemplatetypename.html
• C++11の文法と機能(C++11: Syntax and Feature)
http://ezoeryou.github.io/cpp-book/C++11-Syntax-and-Feature.xhtml
• 一人ぼっちの共鳴 http://dos-sonority.jugem.jp/
• 今更人に聞けないプログラマ用語読み方いろいろ
http://dos-sonority.jugem.jp/?eid=1270