Weitere ähnliche Inhalte Ähnlich wie 中3女子でもわかる constexpr (20) Kürzlich hochgeladen (10) 中3女子でもわかる constexpr1. 中3女子でもわかる!
constexpr
Boost.勉強会 #7
bolero_MURAKAMI
2011/12/3
2. ◆⾃⼰紹介
• 名前 : 村上 原野 (むらかみ げんや)
@bolero_MURAKAMI, id:boleros
• 棲息地: ⼤都会岡⼭
• 仕事 : 猪⾵来美術館陶芸指導員
・普段はやきものの修⾏をしたり、
縄⽂⼟器をつくったりしています
・趣味は constexpr です
3. ◆⾃⼰紹介
• 好きな C++11 の機能:
constexpr
• 嫌いな C++11 のキーワード:
constexpr
• 次期 C++ で強化されてほしい機能:
constexpr
• 次期 C++ で消えてほしいキーワード:
constexpr
5. ◆アジェンダ
• はじめに
• constexpr とは?
• constexpr 実装技法
• constexpr の3⼤コスト
• constexpr ライブラリを使ってみる
• まとめ
6. ◆constexpr とは?
• N3290
7.1.5 The constexpr specifier [dcl.constexpr]
1 The constexpr specifier shall be applied only to the definition of a variable,
the declaration of a function or function template, or the declaration of a
static data member of a literal type (3.9). If any declaration of a function or
function template has constexpr specifier, then all its declarations shall
contain the constexpr specifier. [ Note: An explicit specialization can differ
from the template declaration with respect to the constexpr specifier. -end
note ] [ Note: Function parameters cannot be declared constexpr.-end note ]
7. ◆constexpr とは?
• N3290
7.1.5 constexpr 指定子 [dcl.constexpr]
constexpr 指定子は、変数の定義、関数または関数テンプレートの宣言、
またはリテラル型(3.9)の静的データメンバの宣言に適用されるものとする。
(中略)
[注:関数のパラメータは constexpr 宣言することはできない。]
• C++11 で導⼊されたキーワードである
• decl-specifier に分類される
– (型修飾⼦ではない)
8. ◆constexpr とは?
• constexpr 宣⾔された変数は、コンパイル時定数になる
constexpr int zero = 0; // constexpr 変数
using zero_t = std::integral_constant<int, zero>; // テンプレートにも渡せる
• constexpr 宣⾔された関数やコンストラクタは、コンパ
イル時にも実⾏時にも呼び出すことができる
constexpr int always_zero() { return 0; } // constexpr 関数
constexpr int compiletime_zero = always_zero(); // コンパイル時呼出
int runtime_zero = always_zero(); // 実行時呼出
• リテラル型のオブジェクトは、コンパイル時定数にでき
る
struct literal_type { }; // リテラル型のクラス
constexpr auto literal = literal_type{ }; // クラスインスタンスを定数式に
10. ◆C++ プログラミングのレイヤー
C++03 [処理されるもの] [プログラマのすること]
プリプロセス時の世界 プリプロセッサ
(魔界) ソースコード
メタプログラミング
テンプレート
型
コンパイル時の世界 メタプログラミング
(ライブラリアンが多数棲息)
定数式
実⾏時の世界 実⾏時オブジェクト
(⼈間界)
通常の
プログラミング
11. ◆C++ プログラミングのレイヤー
C++03 [処理されるもの] [プログラマのすること]
プリプロセス時の世界 プリプロセッサ
(魔界) ソースコード
メタプログラミング
テンプレート
型
コンパイル時の世界 メタプログラミング
(ライブラリアンが多数棲息)
定数式
どっちも「値」を
求めるのは同じでも……
わたしたち
離ればなれね……
実⾏時の世界 実⾏時オブジェクト
(⼈間界)
通常の
プログラミング
12. ◆C++ プログラミングのレイヤー
C++11 [処理されるもの] [プログラマのすること]
プリプロセス時の世界 プリプロセッサ
(魔界) ソースコード
メタプログラミング
テンプレート それ constexpr
型 で出来るよ!
コンパイル時の世界 メタプログラミング
(ライブラリアンが多数棲息)
定数式
抱いて!! constexpr
キャーカッコイー!!
実⾏時の世界 実⾏時オブジェクト
(⼈間界)
通常の
プログラミング
13. ◆定数も⾮定数も constexpr で
• TMP で定数値を計算する
typedef typename mpl::max<A, B>::type value_t;
constexpr auto compiletime_value = value_t::value;
• 関数で実⾏時に値を計算する
auto runtime_value = std::max(a, b);
14. ◆定数も⾮定数も constexpr で
• TMP で定数値を計算する
typedef typename mpl::max<A, B>::type value_t;
constexpr auto compiletime_value = value_t::value;
• 関数で実⾏時に値を計算する
auto runtime_value = std::max(a, b);
↓
• どっちも constexpr で出来るよ!
template<class T> // constexpr 関数テンプレート
constexpr T max(T const& a, T const& b) { return a < b ? b : a; }
auto runtime_value = max(a, b); しかも TMP より⾼速
constexpr auto compiletime_value = max(a, b);
16. ◆コンパイル時⽂字列
• TMP でやってみる
typedef mpl::string<’Hell’, ’o, wo’, ’rld! ’> hello_t;
– 書きづらい(醜い)
– 遅い
– 制限が多い
– 型の領域だけでは無理がある
↓ Sprout C++ Library の
• 簡単さ。そう、constexpr ならね constexpr string
#include <sprout/string.hpp>
constexpr auto hello = sprout::to_string(“hello, world!”);
⽂字列リテラルも
そのまま使える
17. ◆コンパイル時⽂字列
• こんなことも出来るよ!
– 例) コンパイル時⽂字列解析 (Boost.Spirit.Qi ⾵)
{
using namespace sprout;
using namespace sprout::weed;
constexpr auto s = to_string("{550E8400-E29B-41D4-A716-446655440000}");
constexpr auto unbracket_uuid_p
= repeat[lim<16>(hex8f)]
| repeat[lim<4>(hex8f)]
>> '-' >> repeat[lim<2>(hex8f)] >> '-' >> repeat[lim<2>(hex8f)]
>> '-' >> repeat[lim<2>(hex8f)] >> '-' >> repeat[lim<6>(hex8f)];
constexpr auto uuid_p
= (unbracket_uuid_p | '{' >> unbracket_uuid_p >> '}') >> eoi;
constexpr auto parsed = parse(s.begin(), s.end(), uuid_p);
std::cout << std::boolalpha << realign_to<uuid>(parsed.attr()) << "¥n";
}
18. ◆コンパイル時⽂字列
• こんなことも出来るよ!
– 例) コンパイル時⽂字列解析 (Boost.Spirit.Qi ⾵)
{
using namespace sprout;
UUID ⽂字列
using namespace sprout::weed;
constexpr auto s = to_string("{550E8400-E29B-41D4-A716-446655440000}");
constexpr auto unbracket_uuid_p ブラケット無しの
= repeat[lim<16>(hex8f)] UUID にマッチするパーサ
| repeat[lim<4>(hex8f)]
>> '-' >> repeat[lim<2>(hex8f)] >> '-' >> repeat[lim<2>(hex8f)]
>> '-' >> repeat[lim<2>(hex8f)] >> '-' >> repeat[lim<6>(hex8f)];
constexpr auto uuid_p ブラケット無し/有り両⽅に
= (unbracket_uuid_p | '{' >> unbracket_uuid_p >> '}') >> eoi; マッチするようパーサを合成
constexpr auto parsed = parse(s.begin(), s.end(), uuid_p); パースを実⾏
std::cout << std::boolalpha << realign_to<uuid>(parsed.attr()) << "¥n";
}
最後以外全部コンパイル時に
処理される
19. ◆constexpr で扱えるデータ
[リテラル型]
[スカラ型] [リテラル型の配列]
[算術型] LiteralType [N]
[整数型] int, unsigned int, char, ...
[リテラル型への参照]
[浮動⼩数点型] float, double, ... LiteralType const&
[ポインタ型]
[ポインタ] int const*, int (*)(void), ...
特定の条件を満たす
[メンバポインタ] int T::*, int (T::*)(void), ...
ユーザ定義クラス
[列挙型] enum
20. ◆リテラル型クラスの条件
• コンパイラの要求
– trivial コピーコンストラクタを持つ
– ⾮ trivial ムーブコンストラクタを持たない
– trivial デストラクタを持つ
– trivial デフォルトコンストラクタか、コピーでもムーブでもな
い constexpr コンストラクタを持つ
– ⾮ static データメンバと基本クラスは、全てリテラル型である
21. ◆リテラル型クラスの条件
• プログラマの「べからず」
– 仮想関数や仮想基底クラスを書かない
– ユーザ定義コピーコンストラクタを書かない
• (delete もしない)
– ユーザ定義ムーブコンストラクタを書かない
• (delete するのはよい)
– ユーザ定義デストラクタを書かない
– ユーザ定義デフォルトコンストラクタを書くなら原則
constexpr にする
• (デフォルトコンストラクタが trivial でも constexpr でもない場
合、別の constexpr コンストラクタを書く)
– リテラル型以外の⾮ static データメンバや基底クラスを使わな
い
22. ◆リテラル型クラスの条件
• リテラル型になれない例
struct NonLiteralType 仮想基底クラスは NG!
: virtual BaseType
: NonLiteralBaseType リテラル型以外の基底クラスは NG!
{ };
struct NonLiteralType {
virtual MemberFunction() const; 仮想関数は NG!
};
ユーザ定義コピーコンストラクタは NG!
struct NonLiteralType {
constexpr LiteralType(LiteralType const&) { }
LiteralType(LiteralType const&) = delete;
};
コピーコンストラクタの delete も NG!
23. ◆リテラル型クラスの条件
• リテラル型になれない例
struct NonLiteralType {
ユーザ定義デストラクタは NG!
~LiteralType() { }
};
デフォルトコンストラクタが⾮ constexpr の場合
struct NonLiteralType { 別の constexpr コンストラクタがあれば OK
LiteralType() { }
// constexpr explicit LiteralType(int) { }
};
ユーザ定義ムーヴコンストラクタは NG!
struct NonLiteralType {
constexpr LiteralType(LiteralType&&) { }
// LiteralType(LiteralType&&) = delete;
};
ムーヴコンストラクタの delete は OK
25. ◆関数を constexpr 化する
• 条件分岐
• ループ
• ローカル変数
• エラー通知
• シグネチャの constexpr 化
• 配列操作 (Variadic function)
• 配列操作 (index_tuple イディオム)
26. ◆条件分岐
• ⾮ constexpr 関数
template<class T>
T max(T const& a, T const& b) {
if (a < b) return b;
else return a;
}
if ⽂
↓
• constexpr 関数 条件演算⼦
template<class T>
constexpr T max(T const& a, T const& b) {
return (a < b) ? b : a;
}
27. ◆ループ
• ⾮ constexpr 関数
template<class Iter, class T>
Iter find(Iter first, Iter last, T const& val) {
while (first != last) {
if (*first == val) return first;
++first;
}
return first;
ループ構⽂
} ↓
再帰
• constexpr 関数
template<class Iter, class T>
constexpr Iter find(Iter first, Iter last, T const& val) {
return (first != last)
? (*first == val) ? first
: find(first + 1, last, val)
: first; ++演算⼦は使えない
} (副作⽤があるから)
28. ◆ループ
• ⾮ constexpr 関数
template<class Iter, class T>
Iter find(Iter first, Iter last, T const& val) {
while (first != last) {
if (*first == val) return first;
++first;
}
return first;
ループ構⽂
} ↓
再帰
• constexpr 関数
template<class Iter, class T>
constexpr Iter find(Iter first, Iter last, T const& val) {
return (first == last) || (*first == val) ? first
: find(first + 1, last, val);
} 式を整理して
このようにも書ける
29. ◆ローカル変数
• ⾮ constexpr 関数
double heron(double a, double b, double c) {
double s = (a+b+c)/2;
return std::sqrt(s*(s-a)*(s-b)*(s-c)); ローカル変数
} ↓
実装⽤関数の引数に
• constexpr 関数
constexpr double heron_impl(double a, double b, double c, double s) {
return std::sqrt(s*(s-a)*(s-b)*(s-c));
}
constexpr double heron(double a, double b, double c) {
return heron_impl(a, b, c, (a+b+c)/2);
}
実装⽤関数
※ constexpr std::sqrt は libstdc++ の⾮標準拡張
30. ◆エラー通知
• ⾮ constexpr 関数
template<class T>
T const* next(T const* p) {
if (p) return p + 1;
else assert(0); // error
}
assert / 実⾏時例外
↓
• constexpr 関数 例外
template<class T>
constexpr T const* next(T const* p) {
return p ? p + 1
: throw std::invalid_argument("p is nullptr");
}
コンパイル時にはコンパイルエラー
実⾏時には例外が投げられる
31. ◆エラー通知
• ⾮ constexpr 関数
template<class T>
T const* next(T const* p) {
if (p) return p + 1;
else assert(0); // error
}
assert / 実⾏時例外
↓
• constexpr 関数 × static_assert
template<class T>
constexpr T const* next(T const* p) {
static_assert(p != 0, "p is nullptr"); // NG!
return p + 1;
} p が実⾏時引数のとき
p !=0 は⾮定数式
32. ◆シグネチャの constexpr 化
• ⾮ constexpr 関数
template<class T>
void inc(T& x) {
++x;
}
返値 void → 値を返す
• constexpr 関数 引数書換え → 副作⽤無しに
template<class T>
constexpr T inc(T const& x) {
return x + 1;
}
33. ◆シグネチャの constexpr 化
• ⾮ constexpr 関数
template<class Iter, class Expr, class Attr>
bool parse(Iter& first, Iter last, Expr const& expr, Attr& attr);
複数の結果(副作⽤)がある
↓
• constexpr 関数 タプルにして返す
template<class Attr, class Iter, class Expr>
constexpr tuple<bool, Iter, Attr> parse(Iter first, Iter last, Expr const& expr);
34. ◆配列操作 (Variadic function)
• reverse アルゴリズムを実装してみる
#include <sprout/array.hpp>
constexpr array
using namespace sprout;
template<class T, size_t N>
constexpr array<T, N> reverse(array<T, N> const& arr);
適⽤結果の配列を返す
35. ◆配列操作 (Variadic function)
• reverse アルゴリズムを実装してみる
template<class T, size_t N, class... Args>
constexpr array<T, N>
reverse_impl(array<T, N> const& arr, Args const&... args) {
return (sizeof...(Args) >= N) 要素全て Parameter pack に追加されるまで
? array<T, N>{{ args... }}
: reverse_impl(arr, args..., arr[N-1-sizeof...(Args)]);
} 配列要素のケツから次々
Parameter pack の末尾に挿⼊
template<class T, size_t N>
constexpr array<T, N> reverse(array<T, N> const& arr) {
return reverse_impl(arr);
}
36. ◆配列操作 (Variadic function)
• reverse アルゴリズムを実装してみる
template<class T, size_t N, class... Args>
constexpr array<T, N>
reverse_impl(array<T, N> const& arr, Args const&... args) {
return (sizeof...(Args) >= N)
? array<T, N>{{ args... }}
: reverse_impl(arr, args..., arr[N-1-sizeof...(Args)]);
}
template<class T, size_t N>
constexpr array<T, N> reverse(array<T, N> const& arr) {
return reverse_impl(arr);
}
• 残念ながら、このコードはコンパイルできない
error: template instantiation depth exceeds maximum of 1024
(use -ftemplate-depth= to increase the maximum)
テンプレート実体化の深さ限界を超えてしまった
37. ◆配列操作 (Variadic function)
• reverse アルゴリズムを実装してみる
template<class T, size_t N, class... Args>
constexpr array<T, N>
reverse_impl(array<T, N> const& arr, Args const&... args) {
return (sizeof...(Args) >= N) sizeof...(Args) == N のとき再帰終了する?
? array<T, N>{{ args... }}
: reverse_impl(arr, args..., arr[N-1-sizeof...(Args)]);
} 「評価」はされないが
「テンプレートの実体化」はされる
template<class T, size_t N> → 実体化の再帰は終了しない
constexpr array<T, N> reverse(array<T, N> const& arr) {
return reverse_impl(arr);
} 結果、テンプレートの実体化が
無限再帰になる
38. ◆配列操作 (Variadic function)
• reverse アルゴリズムを実装してみる
template<class T, size_t N, class... Args>
constexpr typename enable_if<
(sizeof...(Args) >= N), SFINAE: ここで再帰終了
array<T, N>
>::type reverse_impl(array<T, N> const& arr, Args const&... args) {
return array<T, N>{{ args... }};
} 再帰条件を
template<class T, size_t N, class... Args> SFINAE で書く
constexpr typename enable_if<
(sizeof...(Args) < N),
array<T, N>
SFINAE: 再帰を続ける場合
>::type reverse_impl(array<T, N> const& arr, Args const&... args) {
return reverse_impl(arr, args..., arr[N-1-sizeof...(Args)]);
}
template<class T, size_t N>
constexpr array<T, N> reverse(array<T, N> const& arr) {
return reverse_impl(arr);
}
40. ◆配列操作 (index_tuple idiom)
• また reverse アルゴリズムを実装してみる
#include <sprout/array.hpp>
constexpr array
using namespace sprout;
template<class T, size_t N>
constexpr array<T, N> reverse(array<T, N> const& arr);
適⽤結果の配列を返す
41. ◆配列操作 (index_tuple idiom)
• また reverse アルゴリズムを実装してみる
#include <sprout/index_tuple.hpp> for index_tuple, index_range
template<class T, size_t N, ptrdiff_t... Indexes>
constexpr array<T, N>
reverse_impl(array<T, N> const& arr, index_tuple<Indexes...>) {
return array<T, N>{{ arr[N-1-Indexes]... }};
}
template<class T, size_t N>
constexpr array<T, N> reverse(array<T, N> const& arr) {
return reverse_impl(arr, typename index_range<0, N>::type());
}
42. ◆配列操作 (index_tuple idiom)
• また reverse アルゴリズムを実装してみる
#include <sprout/index_tuple.hpp>
template<class T, size_t N, ptrdiff_t... Indexes> 0..N-1 に推論され
constexpr array<T, N> る
reverse_impl(array<T, N> const& arr, index_tuple<Indexes...>) {
return array<T, N>{{ arr[N-1-Indexes]... }};
} Pack expansion expression によって
arr[N-1]..arr[0] に展開される
template<class T, size_t N>
constexpr array<T, N> reverse(array<T, N> const& arr) {
return reverse_impl(arr, typename index_range<0, N>::type());
}
index_range<0, N>::type は
index_tuple<0..N-1> を返す
43. ◆配列操作 (index_tuple idiom)
• index_tuple イディオムは、インデックスアクセス可能
なデータ構造⼀般に適⽤できる
– 配列
– タプル
– ランダムアクセスイテレータ
– 型リスト
• constexpr に限らず、通常の関数や TMP にも同じよう
に応⽤できる
• ただしインデックスアクセス不可なデータ構造には適⽤
できない
– ⾮ランダムアクセスなイテレータなど
45. ◆コンストラクタで処理を委譲
• Delegating constructor
#include <sscrisk/cel/algorithm.hpp> constexpr minmax_element
using namespace sscrisk::cel;
template<class T> あるイテレータ範囲の min と max を
struct minmax_t { 保持するクラス
template<class Iter>
constexpr minmax_t(Iter first, Iter last);
private: constexpr コンストラクタでは
T min_, max_; 初期化⼦リストにしか
}; 処理を書けない
46. ◆コンストラクタで処理を委譲
• Delegating constructor
template<class T>
struct minmax_t { まず minmax を求めてから
template<class Iter> 別のコンストラクタに処理を丸投げ
constexpr minmax_t(Iter first, Iter last)
: minmax_t(minmax_element(first, last))
{}
private:
template<class Iter>
constexpr minmax_t(pair<Iter, Iter> const& minmax)
: min_(*minmax.first)
, max_(*minmax.second) minmax を
min と max に振り分け
{}
T min_, max_;
};
47. ◆コンストラクタで処理を委譲
• C++03 Delegating constructor workaround
template<class T>
struct minmax_t_impl {
protected:
template<class Iter>
constexpr minmax_t_impl(pair<Iter, Iter> const& minmax)
: min_(*minmax.first)
, max_(*minmax.second) 実装⽤クラスで minmax を
{} min と max に振り分け
T min_, max_;
};
private 継承
template<class T>
struct minmax_t : private minmax_t_impl<T> {
template<class Iter> 実装⽤クラスに処理を丸投げ
constexpr minmax_t(Iter first, Iter last)
: minmax_t_impl<T>(minmax_element(first, last))
{}
private:
using minmax_t_impl<T>::min_;
using minmax_t_impl<T>::max_;
}; 実装⽤クラスのメンバを using
48. ◆状態を書き換えるメンバ関数
• ⾮ constexpr クラス
struct sha1 {
void process_byte(unsigned char byte);
template<class Iter>
状態を書き換える
void process_block(Iter first, Iter last);
↓
};
「次の状態」を返すように
• constexprクラス
struct sha1 {
constexpr sha1 process_byte(unsigned char byte) const;
template<class Iter>
constexpr sha1 process_block(Iter first, Iter last) const;
};
49. ◆状態を書き換えるメンバ関数
• ⾮ constexpr クラス
struct random_generator {
unsigned int operator()(); 状態を書き換え、
}; かつ処理結果を返す
↓
処理結果と「次の状態」の
タプルを返す
• constexprクラス
struct random_generator {
constexpr pair<unsigned int, random_generator> operator()() const;
};
51. ◆オブジェクトコピーのコスト
• 配列の2つの要素の swap を考えてみる
– ⾮ constexpr の場合 (元の配列を書換え)
⾼々1回のコピーと
2回の代⼊
(またはムーヴ)
– constexpr の場合 (別の配列をつくる)
常に全要素の
コピー
• 単なる要素の交換に線形時間 O(n) を要する
52. ◆オブジェクトコピーのコスト
• 状態を書き換えるメンバ関数の呼出しを考えてみる
constexpr array<unsigned char, N> src = { /*...*/ };
sha1.process_byte(src[0])
.process_byte(src[1]) 計算量=
/*...*/ (計算毎+コピー毎)×要素数
.process_byte(src[N-1]);
sha1.process_block(src.begin(), src.end());
計算量=計算毎×要素数+コピー
• 状態を書き換えるメンバ関数を constexpr にすると、
(オブジェクトコピー×呼出し回数)の計算量が余計に
かかる
54. ◆再帰とテンプレート実体化のコスト
• 再帰を途中で打ち切るアルゴリズムを考えてみる
template<class T, size_t N, class... Args>
constexpr typename enable_if< SFINAE の番兵
(sizeof...(Args) >= N),
array<T, N>
>::type copy_to_find(array<T, N> const& arr, T const& val, Args const&... args) {
return array<T, N>{{ args... }};
}
template<class T, size_t N, class... Args>
引数 val と等しい要素があったら
constexpr typename enable_if<
そこまでを新しい配列にコピーする
(sizeof...(Args) < N),
array<T, N>
>::type copy_to_find(array<T, N> const& arr, T const& val, Args const&... args) {
return val == arr[sizeof...(Args)] ? array<T, N>{{ args... }}
: find_copy(arr, val, args..., arr[sizeof...(Args)]);
}
55. ◆再帰とテンプレート実体化のコスト
• 再帰を途中で打ち切るアルゴリズムを考えてみる
constexpr auto src_1 = array<int, 10>{{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }};
constexpr auto copied_1 = copy_to_find(src_1, 5);
再帰は 5 まで
要素数が 20
constexpr auto src_2 = array<unsigned, 20>{{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }};
constexpr auto copied_2 = copy_to_find(src_2, 5);
再帰は 5 まで
• copied_1 の計算量は copied_2 と変わらないはず
– ところが、そうはならない (gcc 4.7)
– copied_2 のほうが倍近く遅い
56. ◆再帰とテンプレート実体化のコスト
• 再帰を途中で打ち切るアルゴリズムを考えてみる
constexpr auto src_1 = array<int, 10>{{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }};
constexpr auto copied_1 = copy_to_find(src_1, 5);
constexpr auto src_2 = array<unsigned, 20>{{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }};
constexpr auto copied_2 = copy_to_find(src_2, 5);
• 実際に評価される再帰が何回だったとしても(例え0回
でも)SFINAE で打ち切られるまで全てのテンプレート
がインスタンス化されるため
– (copied_1 は 10,copied_2 は 20)
60. ◆コーディング上のコスト
• 例) constexpr uniform_int_distribution の実装
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_3_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned
brange, BaseUnsigned bucket_size);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_3_1_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange,
BaseUnsigned bucket_size, BaseUnsigned result);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_3_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned
brange, BaseUnsigned bucket_size);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_3(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2_4(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType
result, RangeType result_increment);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2_3(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType
result, RangeType mult, RangeType result_increment);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned, typename Result>
constexpr result<T, Engine> generate_uniform_int_true_2_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType
result, RangeType mult, Result const& result_increment_base);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType
limit, RangeType result = RangeType(0), RangeType mult = RangeType(1));
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2_1_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned
brange, RangeType limit, RangeType result, RangeType mult);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType
limit, RangeType result, RangeType mult);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange);
template<typename Engine, typename T, typename BaseResult>
constexpr result<T, Engine> generate_uniform_int_true_1_1(random_result<Engine> const& rnd, T min_value, BaseResult bmin);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_1(Engine const& eng, T min_value, T max_value, RangeType range, BaseResult bmin, BaseUnsigned brange);
template<typename Engine, typename T>
constexpr result<T, Engine> generate_uniform_int(Engine const& eng, T min_value, T max_value, std::true_type);
template<typename Engine, typename T, typename Result>
constexpr result<T, Engine> generate_uniform_int_false_1(Result const& rnd);
template<typename Engine, typename T>
61. ◆コーディング上のコスト
• 実装関数が増殖する
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_3_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned
brange, BaseUnsigned bucket_size);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_3_1_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange,
BaseUnsigned bucket_size, BaseUnsigned result);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_3_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned
brange, BaseUnsigned bucket_size);
これは宣⾔だけ書き出して⼀部省略しているので
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
引数コピペの嵐 実際のコードはもっと酷い
constexpr result<T, Engine> generate_uniform_int_true_3(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange);
元々はたった
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2_4(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType
2 個の関数だった
result, RangeType result_increment);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2_3(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType
18 個の実装関数
result, RangeType mult, RangeType result_increment);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned, typename Result>
constexpr result<T, Engine> generate_uniform_int_true_2_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType
result, RangeType mult, Result const& result_increment_base);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType
limit, RangeType result = RangeType(0), RangeType mult = RangeType(1));
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2_1_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned
brange, RangeType limit, RangeType result, RangeType mult);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType
limit, RangeType result, RangeType mult);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange);
template<typename Engine, typename T, typename BaseResult>
constexpr result<T, Engine> generate_uniform_int_true_1_1(random_result<Engine> const& rnd, T min_value, BaseResult bmin);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_1(Engine const& eng, T min_value, T max_value, RangeType range, BaseResult bmin, BaseUnsigned brange);
template<typename Engine, typename T>
constexpr result<T, Engine> generate_uniform_int(Engine const& eng, T min_value, T max_value, std::true_type);
template<typename Engine, typename T, typename Result>
constexpr result<T, Engine> generate_uniform_int_false_1(Result const& rnd);
template<typename Engine, typename T>
62. ◆コーディング上のコスト
• 名前付けが酷い
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_3_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned
brange, BaseUnsigned bucket_size);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_3_1_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange,
generate_uniform_int_true_2_1 とか
BaseUnsigned bucket_size, BaseUnsigned result);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_3_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned
brange, BaseUnsigned bucket_size); generate_uniform_int_true_2_2 とか
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
generate_uniform_int_true_2_3 ...
constexpr result<T, Engine> generate_uniform_int_true_3(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2_4(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType
result, RangeType result_increment); そもそも意味論でなく単に処理フローで
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
分割しているだけなので、
constexpr result<T, Engine> generate_uniform_int_true_2_3(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType
result, RangeType mult, RangeType result_increment);
各関数に意味のある名前を付けるのが難しい
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned, typename Result>
constexpr result<T, Engine> generate_uniform_int_true_2_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType
result, RangeType mult, Result const& result_increment_base);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType
limit, RangeType result = RangeType(0), RangeType mult = RangeType(1));
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2_1_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned
constexpr ラムダ式があれば
brange, RangeType limit, RangeType result, RangeType mult);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
救われる(かもしれない)
constexpr result<T, Engine> generate_uniform_int_true_2_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType
limit, RangeType result, RangeType mult);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange);
template<typename Engine, typename T, typename BaseResult>
constexpr result<T, Engine> generate_uniform_int_true_1_1(random_result<Engine> const& rnd, T min_value, BaseResult bmin);
template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>
constexpr result<T, Engine> generate_uniform_int_true_1(Engine const& eng, T min_value, T max_value, RangeType range, BaseResult bmin, BaseUnsigned brange);
template<typename Engine, typename T>
constexpr result<T, Engine> generate_uniform_int(Engine const& eng, T min_value, T max_value, std::true_type);
template<typename Engine, typename T, typename Result>
constexpr result<T, Engine> generate_uniform_int_false_1(Result const& rnd);
template<typename Engine, typename T>
64. ◆constexpr なライブラリ
• 標準ライブラリ
• libstdc++ 独⾃拡張
• CEL - ConstExpr Library
• Sprout C++ Library
65. ◆標準ライブラリ
• <limits>
– numeric_limits
• <utility>
– pair (デフォルトコンストラクタのみ)
• <tuple>
– tuple (デフォルトコンストラクタのみ)
• <bitset>
– bitset
• <memory>
– unique_ptr (デフォルトコンストラクタのみ)
– shared_ptr (デフォルトコンストラクタのみ)
– weak_ptr (デフォルトコンストラクタのみ)
– enable_shared_from_this (デフォルトコンストラクタのみ)
66. ◆標準ライブラリ
• <ratio>
– ratio
• <chrono>
– 各種演算
– duration_values
– duration
– time_point
• <string>
– char_traits
• <array>
– array (size, max_size, empty のみ)
• <iterator>
– istream_iterator (デフォルトコンストラクタのみ)
– istreambuf_iterator (デフォルトコンストラクタのみ)
67. ◆標準ライブラリ
• <complex>
– complex
• <random>
– 各種⽣成器クラス (min, max のみ)
• <regex>
– sub_match (デフォルトコンストラクタのみ)
• <atomic>
– atomic (コンストラクタのみ)
• <mutex>
– mutex (デフォルトコンストラクタのみ)
68. ◆標準ライブラリ
• 標準ライブラリの⽅針としては、「通常
の使⽤において、ほぼ⾃明にコンパイル
時処理にできる」ものだけを constexpr
指定しているようだ
– bitset
– ratio
– chrono など
• numeric_limits が使える⼦になった
• 保守的な⽅針
69. ◆libstdc++ 独⾃拡張
(GCC 4.7 experimental)
• <cmath>
– 各種関数
• <tuple>
– tuple
• <utility>
– forward, move
70. ◆libstdc++ 独⾃拡張
• <cmath> が constexpr 化されてるのが
⼤きい
– これに依存する前提なら多くの数学計算の
constexpr 化が楽になる
• なんで <array> が constexpr じゃない
のか……
71. ◆CEL - ConstExpr Library
• 作者: RiSK (@sscrisk) さん
– https://github.com/sscrisk/CEL---ConstExpr-Library
• <algorithm>
• <numeric>
• <cstdlib>
• <cstring>
• <iterator>
– 各種アルゴリズム (⾮ Mutating な部分)
72. ◆CEL - ConstExpr Library
• <cctype>
– ⽂字列判定
• <functional>
– 関数オブジェクト
• <array>
– array
• <utility>
– pair
73. ◆CEL - ConstExpr Library
• 標準ライブラリの関数の「シグネチャの
変更なしに constexpr 化できるもの」を
ほぼ⼀通りカバーしている
74. ◆Sprout C++ Library
• constexpr ⽂字列
• constexpr タプル
• constexpr バリアント
• constexpr アルゴリズム
• constexpr 範囲アルゴリズム
• constexpr コンテナ操作
• constexpr 乱数
• constexpr ハッシュ関数
• constexpr UUID
• constexpr 構⽂解析
• constexpr レイトレーシング
75. ◆constexpr ⽂字列
• Sprout.String
#include <sprout/string.hpp>
#include <iostream>
int main() {
using namespace sprout;
constexpr string<6> hello = to_string("Hello ");
constexpr string<6> world = to_string("world!");
constexpr auto str = hello + world;
std::cout << str << "¥n"; // "Hello world!"
constexpr auto hell = str.substr(0, 4);
std::cout << hell << "¥n"; // "Hell"
}
76. ◆constexpr ⽂字列
• Sprout.String
#include <sprout/string.hpp>
#include <iostream>
型には要素数(最⼤⽂字数)が含まれる
int main() {
using namespace sprout;
constexpr string<6> hello = to_string("Hello ");
constexpr string<6> world = to_string("world!");
要素数が増える場合:
constexpr auto str = hello + world; string<N> + string<M>
std::cout << str << "¥n"; // "Hello world!" → string<N + M>
constexpr auto hell = str.substr(0, 4);
std::cout << hell << "¥n"; // "Hell" 要素数が減る場合:
} string<N>::substr
→ string<N>
77. ◆constexpr ⽂字列
• Sprout.String 実装
namespace sprout {
template<class T, size_t N, Traits = char_traits<T> >
class basic_string {
T elems [N + 1]; ヌル終端を含めた固定⻑バッファ
size_t len;
}; ⽂字列⻑ (len <= N)
}
• ⽂字列⻑が変わる操作:
– 静的に決定できる場合は型レベルで解決
– そうでなければ len を弄って変更
– あるいはユーザ側に最⼤⻑を指定させる
78. ◆constexpr アルゴリズム
• Sprout.Algorithm
#include <sprout/algorithm.hpp>
#include <iostream>
int main() {
using namespace sprout;
constexpr auto arr = make_array<int>(5, 1, 9, 4, 8, 2, 7, 3, 10, 6);
配列をソート
constexpr auto sorted = sort(arr);
for (auto i : sorted) { std::cout << i << ' '; }
std::cout << "¥n"; // 1 2 3 4 5 6 7 8 9 10
配列を反転
constexpr auto reversed = reverse(sorted);
for (auto i : reversed) { std::cout << i << ' '; }
std::cout << "¥n"; // 10 9 8 7 6 5 4 3 2 1
}
79. ◆constexpr アルゴリズム
• Sprout.Algorithm
– 主に Mutating sequence operations をカバーする
• CEL と合わせれば STL のアルゴリズムはほぼ全てカ
バーできる
• RandomAccessIterator に対しては index_tuple イ
ディオムで効率的に処理する
– ユーザ側で sprout::next/prev をオーバーロードすることで
InputIterator なども渡せる
• それ以外の IteratorCategory は Variadic Function で
実装されている
80. ◆constexpr 乱数
• Sprout.Random
#include <sprout/random.hpp>
#include <sprout/random/unique_seed.hpp>
#include <sprout/array.hpp>
#include <sprout/algorithm.hpp>
#include <iostream>
int main() {
using namespace sprout;
constexpr auto arr = make_array<int>(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
constexpr std::size_t seed = SPROUT_UNIQUE_SEED;
constexpr auto engine = minstd_rand0(seed);
constexpr auto distribution = uniform_smallint<int>(1, 6);
constexpr auto shuffled = shuffle(arr, random::combine(engine, distribution));
for (auto i : shuffled) { std::cout << i << ' '; }
std::cout << "¥n";
}
81. ◆constexpr 乱数
• Sprout.Random
#include <sprout/random.hpp>
#include <sprout/random/unique_seed.hpp>
#include <sprout/array.hpp>
#include <sprout/algorithm.hpp> ⽇時とファイル名と⾏の
#include <iostream> ⽂字列からハッシュ値を
⽣成するマクロ
int main() {
using namespace sprout;
constexpr auto arr = make_array<int>(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
constexpr std::size_t seed = SPROUT_UNIQUE_SEED; 線形合同法エンジン
constexpr auto engine = minstd_rand0(seed);
constexpr auto distribution = uniform_smallint<int>(1, 6); 整数⼀様分布
constexpr auto shuffled = shuffle(arr, random::combine(engine, distribution));
for (auto i : shuffled) { std::cout << i << ' '; }
std::cout << "¥n"; ランダムシャッフル
}
82. ◆constexpr 乱数
• Sprout.Random
– <random> と同じく様々な乱数⽣成器と分布を提供する
• 関数型⾔語にならって、乱数⽣成器は「⽣成した値」
「次の状態の⽣成器」のペアを返す仕様
• コンパイル時に取得できる値でシードに使えるものが
__DATA__ __FILE__ __LINE__ くらいしかないので
それを使う
83. ◆constexpr 構⽂解析
• Sprout.Weed
#include <sprout/weed.hpp>
#include <sprout/string.hpp>
#include <sprout/uuid.hpp>
Int main() {
using namespace sprout;
using namespace sprout::weed;
constexpr auto s = to_string("{550E8400-E29B-41D4-A716-446655440000}");
constexpr auto unbracket_uuid_p
= repeat[lim<16>(hex8f)]
| repeat[lim<4>(hex8f)]
>> '-' >> repeat[lim<2>(hex8f)] >> '-' >> repeat[lim<2>(hex8f)]
>> '-' >> repeat[lim<2>(hex8f)] >> '-' >> repeat[lim<6>(hex8f)];
constexpr auto uuid_p
= (unbracket_uuid_p | '{' >> unbracket_uuid_p >> '}') >> eoi;
constexpr auto parsed = parse(s.begin(), s.end(), uuid_p);
}
84. ◆constexpr 構⽂解析
• Sprout.Weed
#include <sprout/weed.hpp>
#include <sprout/string.hpp>
#include <sprout/uuid.hpp> hex8f : 8bit16進数にマッチ
Int main() {
using namespace sprout;
using namespace sprout::weed;
constexpr auto s = to_string("{550E8400-E29B-41D4-A716-446655440000}");
constexpr auto unbracket_uuid_p
= repeat[lim<16>(hex8f)]
| repeat[lim<4>(hex8f)]
>> '-' >> repeat[lim<2>(hex8f)] >> '-' >> repeat[lim<2>(hex8f)]
>> '-' >> repeat[lim<2>(hex8f)] >> '-' >> repeat[lim<6>(hex8f)];
constexpr auto uuid_p
= (unbracket_uuid_p | '{' >> unbracket_uuid_p >> '}') >> eoi;
constexpr auto parsed = parse(s.begin(), s.end(), uuid_p);
}
85. ◆constexpr 構⽂解析
• Sprout.Weed
#include <sprout/weed.hpp>
#include <sprout/string.hpp> repeat : lim<N>回の繰り返し
#include <sprout/uuid.hpp> array<Attr, N * M>
Int main() {
using namespace sprout;
using namespace sprout::weed;
constexpr auto s = to_string("{550E8400-E29B-41D4-A716-446655440000}");
constexpr auto unbracket_uuid_p
= repeat[lim<16>(hex8f)]
| repeat[lim<4>(hex8f)]
>> '-' >> repeat[lim<2>(hex8f)] >> '-' >> repeat[lim<2>(hex8f)]
>> '-' >> repeat[lim<2>(hex8f)] >> '-' >> repeat[lim<6>(hex8f)];
constexpr auto uuid_p
= (unbracket_uuid_p | '{' >> unbracket_uuid_p >> '}') >> eoi;
constexpr auto parsed = parse(s.begin(), s.end(), uuid_p);
}
86. ◆constexpr 構⽂解析
• Sprout.Weed
#include <sprout/weed.hpp>
#include <sprout/string.hpp> >> : パーサの連結
#include <sprout/uuid.hpp> array<Attr, N + M>
Int main() {
using namespace sprout;
using namespace sprout::weed;
constexpr auto s = to_string("{550E8400-E29B-41D4-A716-446655440000}");
constexpr auto unbracket_uuid_p
= repeat[lim<16>(hex8f)]
| repeat[lim<4>(hex8f)]
>> '-' >> repeat[lim<2>(hex8f)] >> '-' >> repeat[lim<2>(hex8f)]
>> '-' >> repeat[lim<2>(hex8f)] >> '-' >> repeat[lim<6>(hex8f)];
constexpr auto uuid_p
= (unbracket_uuid_p | '{' >> unbracket_uuid_p >> '}') >> eoi;
constexpr auto parsed = parse(s.begin(), s.end(), uuid_p);
}
87. ◆constexpr 構⽂解析
• Sprout.Weed
#include <sprout/weed.hpp>
#include <sprout/string.hpp> | : パーサのOR
#include <sprout/uuid.hpp> variant<Attr1, Attr2>
Int main() {
using namespace sprout;
using namespace sprout::weed;
constexpr auto s = to_string("{550E8400-E29B-41D4-A716-446655440000}");
constexpr auto unbracket_uuid_p
= repeat[lim<16>(hex8f)]
| repeat[lim<4>(hex8f)]
>> '-' >> repeat[lim<2>(hex8f)] >> '-' >> repeat[lim<2>(hex8f)]
>> '-' >> repeat[lim<2>(hex8f)] >> '-' >> repeat[lim<6>(hex8f)];
constexpr auto uuid_p
= (unbracket_uuid_p | '{' >> unbracket_uuid_p >> '}') >> eoi;
constexpr auto parsed = parse(s.begin(), s.end(), uuid_p);
}
88. ◆constexpr 構⽂解析
• Sprout.Weed
– Boost.Spirit.Qi のような Expression Template ベースの
EDSL 構⽂解析ライブラリ
• Expression Template 技法では、処理が細かい単位に
分割されるので、constexpr 化しやすい
• constexpr の導⼊によって、コンパイル時⽂字列処理が
相当⼿軽に出来るようになった
• おそらく今後 constexpr 正規表現などのライブラリも
出てくると思われる
90. ◆constexpr レイトレーシング
• Sprout.Darkroom
#include <sprout/darkroom.hpp> 512×512 pixel
#include <iostream> で作成
static constexpr std::size_t total_width = 512;
static constexpr std::size_t total_height = 512;
static constexpr std::size_t tile_width = 16;
static constexpr std::size_t tile_height = 16;
static constexpr std::size_t offset_x = 0;
static constexpr std::size_t offset_y = 0;
using namespace sprout;
using namespace sprout::darkroom;
91. ◆constexpr レイトレーシング
• Sprout.Darkroom
constexpr auto object = make_tuple(
objects::make_sphere(
coords::vector3d(-1.0, -0.5, 5.0),
1.0, オブジェクトの定義
materials::make_material_image( (2つの球)
colors::rgb_f(1.0, 0.75, 0.75), 0.2)
),
objects::make_sphere(
coords::vector3d(0.5, 0.5, 3.5),
1.0,
materials::make_material_image(
colors::rgb_f(0.75, 0.75, 1.0), 0.2)
)
);
92. ◆constexpr レイトレーシング
• Sprout.Darkroom
光源の定義
(点光源)
constexpr auto light = lights::make_point_light(
coords::vector3d(1.0, 0.5, 1.0),
colors::rgb_f(3.0, 3.0, 3.0));
constexpr auto camera = cameras::make_simple_camera(1.0);
constexpr auto renderer = renderers::whitted_style();
constexpr auto raytracer = tracers::raytracer<>();
カメラ
レンダラ
レイトレーサー
93. ◆constexpr レイトレーシング
• Sprout.Darkroom
ピクセル⽣成
typedef pixels::color_pixels<tile_width, tile_height>::type image_type;
constexpr auto image = pixels::generate<image_type>(
raytracer, renderer, camera, object, light,
offset_x, offset_y, total_width, total_height);
94. ◆constexpr レイトレーシング
• Sprout.Darkroom
std::cout
<< "P3" << std::endl
<< image[0].size() << ' ' << image.size() << std::endl
<< 255 << std::endl
;
for (auto const& line : image) { 標準出⼒へ
for (auto const& pixel : line) { ppm 形式で出⼒
std::cout
<< unsigned(colors::r(pixel)) << ' '
<< unsigned(colors::g(pixel)) << ' '
<< unsigned(colors::b(pixel)) << std::endl;
}
}
}
95. ◆constexpr レイトレーシング
• Sprout.Darkroom
– metatrace という TMP ライブラリを元にした constexpr レイ
トレーサーライブラリ
• レイトレーシングの基本的なアルゴリズムはとてもシン
プル
• 視点から各ピクセルを通る光線を⾶ばして、ベクトルが
オブジェクトと衝突する部分の拡散光と反射光の成分を
得るだけ
96. ◆次期 C++1x に期待すること
• いくつかのポインタ演算を定数式扱いに
p1 < p2; ポインタの⼤⼩⽐較はできない
p1 - p2; ポインタ同⼠の減算はできない
static_cast<int const*>( static_cast<void const*>(p) )
void* から他の型への読み替えはできない
• union の任意のメンバでの初期化を定数式扱いに
union U {
X x; Y y;
constexpr U() : y() { }
};
先頭メンバ以外での初期化はできない
97. ◆次期 C++1x に期待すること
• ラムダ式を定数式扱いに
template<class F>
constexpr auto call(F f) -> decltype(f()) { return f(); }
call( []{ return 0; } );
constexpr 関数にラムダ式を渡せない
• new/delete を定数式に出来るように
• 標準ライブラリを更に constexpr 化
98. ◆constexpr 化できそうなもの
• 正規表現
– Regex / Expressive
• 汎⽤ Expression Template
– Proto
• シリアライズ
– Serialization
• 画像処理
– GIL
• 数学関数
– Math.SpecialFunction
• etc...