100
中3女子でもわかる! constexpr Boost.勉強会 #7 bolero_MURAKAMI 2011/12/3

中3女子でもわかる constexpr

Embed Size (px)

DESCRIPTION

Boost.勉強会 #7 中3女子でもわかる constexpr

Citation preview

Page 1: 中3女子でもわかる constexpr

中3女子でもわかる! constexpr

Boost.勉強会

#7bolero_MURAKAMI2011/12/3

Page 2: 中3女子でもわかる constexpr

◆⾃⼰紹介•

名前

:

村上

原野

(むらかみ

げんや)

@bolero_MURAKAMI, id:boleros

棲息地:

⼤都会岡⼭

仕事

:

猪⾵来美術館陶芸指導員・普段はやきものの修⾏をしたり、

縄⽂⼟器をつくったりしています・趣味は

constexpr です

Page 3: 中3女子でもわかる constexpr

◆⾃⼰紹介•

好きな

C++11 の機能:

constexpr•

嫌いな

C++11 のキーワード:

constexpr•

次期

C++ で強化されてほしい機能:

constexpr•

次期

C++ で消えてほしいキーワード:

constexpr

Page 4: 中3女子でもわかる constexpr

◆⾃⼰紹介•

公開しているライブラリ:

Sprout C++ Library (constexpr ライブラリ)github.com/bolero-MURAKAMI/Sprout

Page 5: 中3女子でもわかる constexpr

◆アジェンダ•

はじめに

constexpr とは?•

constexpr 実装技法

constexpr の3⼤コスト•

constexpr ライブラリを使ってみる

まとめ

Page 6: 中3女子でもわかる constexpr

◆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 ]

Page 7: 中3女子でもわかる constexpr

◆constexpr とは?•

N3290

C++11 で導⼊されたキーワードである

decl-specifier に分類される–

(型修飾⼦ではない)

7.1.5 constexpr 指定子 [dcl.constexpr]

constexpr 指定子は、変数の定義、関数または関数テンプレートの宣言、またはリテラル型(3.9)の静的データメンバの宣言に適用されるものとする。

(中略)[注:関数のパラメータは

constexpr 宣言することはできない。]

Page 8: 中3女子でもわかる constexpr

◆constexpr とは?•

constexpr 宣⾔された変数は、コンパイル時定数になる

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{ }; // クラスインスタンスを定数式に

constexpr int zero = 0; // constexpr 変数using zero_t = std::integral_constant<int, zero>; // テンプレートにも渡せる

Page 9: 中3女子でもわかる constexpr

◆constexpr ⼊⾨•

プログラミングの魔導書vol.2 の江添さん

の記事を読んでください•

読んでなかったら買ってください

Page 10: 中3女子でもわかる constexpr

◆C++ プログラミングのレイヤー

プリプロセス時の世界(魔界)

コンパイル時の世界(ライブラリアンが多数棲息)

実⾏時の世界(⼈間界)

[プログラマのすること][処理されるもの]

ソースコードプリプロセッサ

メタプログラミング

テンプレートメタプログラミング型

実⾏時オブジェクト

定数式

通常のプログラミング

C++03

Page 11: 中3女子でもわかる constexpr

◆C++ プログラミングのレイヤー

プリプロセス時の世界(魔界)

コンパイル時の世界(ライブラリアンが多数棲息)

実⾏時の世界(⼈間界)

[プログラマのすること][処理されるもの]

ソースコードプリプロセッサ

メタプログラミング

テンプレートメタプログラミング型

実⾏時オブジェクト

定数式

通常のプログラミング

どっちも「値」を求めるのは同じでも…… わたしたち

離ればなれね……

C++03

Page 12: 中3女子でもわかる constexpr

◆C++ プログラミングのレイヤー

プリプロセス時の世界(魔界)

コンパイル時の世界(ライブラリアンが多数棲息)

実⾏時の世界(⼈間界)

[プログラマのすること][処理されるもの]

constexpr

ソースコードプリプロセッサ

メタプログラミング

テンプレートメタプログラミング型

実⾏時オブジェクト

定数式

通常のプログラミング

それ

constexprで出来るよ!

抱いて!!

キャーカッコイー!!

C++11

Page 13: 中3女子でもわかる constexpr

◆定数も⾮定数も

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);

Page 14: 中3女子でもわかる constexpr

◆定数も⾮定数も

constexpr

で•

TMP で定数値を計算する

関数で実⾏時に値を計算する

↓•

どっちも

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);constexpr auto compiletime_value = max(a, b);

typedef typename mpl::max<A, B>::type value_t;constexpr auto compiletime_value = value_t::value;

auto runtime_value = std::max(a, b);

しかも

TMP より⾼速

Page 15: 中3女子でもわかる constexpr

◆コンパイル時⽂字列•

TMP でやってみる

書きづらい(醜い)–

遅い

制限が多い–

型の領域だけでは無理がある

typedef mpl::string<’Hell’, ’o, wo’, ’rld! ’> hello_t;

Page 16: 中3女子でもわかる constexpr

◆コンパイル時⽂字列•

TMP でやってみる

書きづらい(醜い)–

遅い

制限が多い–

型の領域だけでは無理がある

↓•

簡単さ。そう、constexpr ならね

#include <sprout/string.hpp>

constexpr auto hello = sprout::to_string(“hello, world!”);

typedef mpl::string<’Hell’, ’o, wo’, ’rld! ’> hello_t;

Sprout C++ Library のconstexpr string

⽂字列リテラルもそのまま使える

Page 17: 中3女子でもわかる constexpr

◆コンパイル時⽂字列•

こんなことも出来るよ!–

例) コンパイル時⽂字列解析

(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";}

Page 18: 中3女子でもわかる constexpr

◆コンパイル時⽂字列•

こんなことも出来るよ!–

例) コンパイル時⽂字列解析

(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";}

UUID ⽂字列

ブラケット無しのUUID にマッチするパーサ

ブラケット無し/有り両⽅にマッチするようパーサを合成

パースを実⾏

最後以外全部コンパイル時に処理される

Page 19: 中3女子でもわかる constexpr

◆constexpr で扱えるデータ[リテラル型]

[スカラ型] [リテラル型の配列]LiteralType [N]

[リテラル型への参照]LiteralType const&

[算術型]

[整数型] int, unsigned int, char, ...

[浮動⼩数点型] float, double, ...

[ポインタ型]

[ポインタ] int const*, int (*)(void), ...

[メンバポインタ] int T::*, int (T::*)(void), ...

[列挙型] enum

特定の条件を満たすユーザ定義クラス

Page 20: 中3女子でもわかる constexpr

◆リテラル型クラスの条件•

コンパイラの要求–

trivial コピーコンストラクタを持つ

trivial ムーブコンストラクタを持たない–

trivial デストラクタを持つ

trivial デフォルトコンストラクタか、コピーでもムーブでもな い

constexpr コンストラクタを持つ

static データメンバと基本クラスは、全てリテラル型である

Page 21: 中3女子でもわかる constexpr

◆リテラル型クラスの条件•

プログラマの「べからず」–

仮想関数や仮想基底クラスを書かない

ユーザ定義コピーコンストラクタを書かない•

(delete もしない)

ユーザ定義ムーブコンストラクタを書かない•

(delete するのはよい)

ユーザ定義デストラクタを書かない–

ユーザ定義デフォルトコンストラクタを書くなら原則

constexpr にする•

(デフォルトコンストラクタが

trivial でも

constexpr でもない場

合、別の

constexpr コンストラクタを書く)–

リテラル型以外の⾮

static データメンバや基底クラスを使わな

Page 22: 中3女子でもわかる constexpr

◆リテラル型クラスの条件•

リテラル型になれない例

struct NonLiteralType: virtual BaseType: NonLiteralBaseType

{ };

struct NonLiteralType {virtual MemberFunction() const;

};

struct NonLiteralType {constexpr LiteralType(LiteralType const&) { }LiteralType(LiteralType const&) = delete;

};

仮想基底クラスは

NG!

リテラル型以外の基底クラスは

NG!

仮想関数は

NG!

ユーザ定義コピーコンストラクタは

NG!

コピーコンストラクタの

delete も

NG!

Page 23: 中3女子でもわかる constexpr

◆リテラル型クラスの条件•

リテラル型になれない例

struct NonLiteralType {~LiteralType() { }

};

struct NonLiteralType {LiteralType() { }// constexpr explicit LiteralType(int) { }

};

struct NonLiteralType {constexpr LiteralType(LiteralType&&) { }// LiteralType(LiteralType&&) = delete;

};

ユーザ定義デストラクタは

NG!

ユーザ定義ムーヴコンストラクタは

NG!

ムーヴコンストラクタの

delete は

OK

デフォルトコンストラクタが⾮

constexpr の場合別の

constexpr コンストラクタがあれば

OK

Page 24: 中3女子でもわかる constexpr

◆リテラル型クラスの条件•

リテラル型になれない例

struct NonLiteralType {private:

NonLiteralDataType data_member_;};

リテラル型以外のデータメンバは

NG!

Page 25: 中3女子でもわかる constexpr

◆関数を

constexpr 化する•

条件分岐

ループ•

ローカル変数

エラー通知•

シグネチャの

constexpr 化

配列操作

(Variadic function)•

配列操作

(index_tuple イディオム)

Page 26: 中3女子でもわかる constexpr

◆条件分岐•

⾮ constexpr 関数

constexpr 関数

template<class T>T max(T const& a, T const& b) {

if (a < b) return b;else return a;

}

template<class T>constexpr T max(T const& a, T const& b) {

return (a < b) ? b : a;}

if ⽂↓

条件演算⼦

Page 27: 中3女子でもわかる constexpr

◆ループ•

⾮ constexpr 関数

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;

}

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;

}

ループ構⽂↓

再帰

++演算⼦は使えない(副作⽤があるから)

Page 28: 中3女子でもわかる constexpr

◆ループ•

⾮ constexpr 関数

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;

}

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);

}

ループ構⽂↓

再帰

式を整理してこのようにも書ける

Page 29: 中3女子でもわかる constexpr

◆ローカル変数•

⾮ constexpr 関数

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 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++ の⾮標準拡張

Page 30: 中3女子でもわかる constexpr

◆エラー通知•

⾮ constexpr 関数

constexpr 関数

template<class T>T const* next(T const* p) {

if (p) return p + 1;else assert(0); // error

}

template<class T>constexpr T const* next(T const* p) {

return p ? p + 1: throw std::invalid_argument("p is nullptr");

}

assert / 実⾏時例外↓

例外

コンパイル時にはコンパイルエラー実⾏時には例外が投げられる

Page 31: 中3女子でもわかる constexpr

◆エラー通知•

⾮ constexpr 関数

constexpr 関数

template<class T>T const* next(T const* p) {

if (p) return p + 1;else assert(0); // error

}

template<class T>constexpr T const* next(T const* p) {

static_assert(p != 0, "p is nullptr"); // NG!return p + 1;

}

assert / 実⾏時例外↓

×

static_assert

p

が実⾏時引数のときp !=0

は⾮定数式

Page 32: 中3女子でもわかる constexpr

◆シグネチャの

constexpr 化•

⾮ constexpr 関数

constexpr 関数

template<class T>void inc(T& x) {

++x;}

template<class T>constexpr T inc(T const& x) {

return x + 1;}

返値

void →

値を返す

引数書換え

副作⽤無しに

Page 33: 中3女子でもわかる constexpr

◆シグネチャの

constexpr 化•

⾮ constexpr 関数

constexpr 関数

template<class Iter, class Expr, class Attr>bool parse(Iter& first, Iter last, Expr const& expr, Attr& attr);

template<class Attr, class Iter, class Expr>constexpr tuple<bool, Iter, Attr> parse(Iter first, Iter last, Expr const& expr);

複数の結果(副作⽤)がある↓

タプルにして返す

Page 34: 中3女子でもわかる constexpr

◆配列操作

(Variadic function)•

reverse アルゴリズムを実装してみる

#include <sprout/array.hpp>using namespace sprout;

template<class T, size_t N>constexpr array<T, N> reverse(array<T, N> const& arr);

constexpr array

適⽤結果の配列を返す

Page 35: 中3女子でもわかる constexpr

◆配列操作

(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);}

配列要素のケツから次々Parameter pack の末尾に挿⼊

要素全て

Parameter pack に追加されるまで

Page 36: 中3女子でもわかる constexpr

◆配列操作

(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)

テンプレート実体化の深さ限界を超えてしまった

Page 37: 中3女子でもわかる constexpr

◆配列操作

(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);}

sizeof...(Args) == N

のとき再帰終了する?

結果、テンプレートの実体化が無限再帰になる

「評価」はされないが「テンプレートの実体化」はされる

実体化の再帰は終了しない

Page 38: 中3女子でもわかる constexpr

◆配列操作

(Variadic function)•

reverse アルゴリズムを実装してみる

template<class T, size_t N, class... Args>constexpr typename enable_if<

(sizeof...(Args) >= N),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>constexpr typename enable_if<

(sizeof...(Args) < N),array<T, N>

>::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);}

SFINAE: ここで再帰終了

SFINAE: 再帰を続ける場合

再帰条件をSFINAE で書く

Page 39: 中3女子でもわかる constexpr

◆配列操作

(Variadic function)•

Variadic function の再帰はテンプレート実体化の無限

再帰になりやすいので注意する

そうなるケースでは再帰条件を

SFINAE にする

(static if ほしいです)

Page 40: 中3女子でもわかる constexpr

◆配列操作

(index_tuple idiom)•

また

reverse アルゴリズムを実装してみる

#include <sprout/array.hpp>using namespace sprout;

template<class T, size_t N>constexpr array<T, N> reverse(array<T, N> const& arr);

constexpr array

適⽤結果の配列を返す

Page 41: 中3女子でもわかる constexpr

◆配列操作

(index_tuple idiom)•

また

reverse アルゴリズムを実装してみる

#include <sprout/index_tuple.hpp>

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());}

for index_tuple, index_range

Page 42: 中3女子でもわかる constexpr

◆配列操作

(index_tuple idiom)•

また

reverse アルゴリズムを実装してみる

#include <sprout/index_tuple.hpp>

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());}

index_range<0, N>::type は index_tuple<0..N-1> を返す

0..N-1 に推論され る

Pack expansion expression によってarr[N-1]..arr[0] に展開される

Page 43: 中3女子でもわかる constexpr

◆配列操作

(index_tuple idiom)•

index_tuple イディオムは、インデックスアクセス可能

なデータ構造⼀般に適⽤できる–

配列

タプル–

ランダムアクセスイテレータ

型リスト

constexpr に限らず、通常の関数や

TMP にも同じよう に応⽤できる

ただしインデックスアクセス不可なデータ構造には適⽤ できない

⾮ランダムアクセスなイテレータなど

Page 44: 中3女子でもわかる constexpr

◆クラスを

constexpr 化する•

コンストラクタで処理を委譲

状態を書き換えるメンバ関数の constexpr 化

Page 45: 中3女子でもわかる constexpr

◆コンストラクタで処理を委譲•

Delegating constructor

#include <sscrisk/cel/algorithm.hpp>using namespace sscrisk::cel;

template<class T>struct minmax_t {

template<class Iter>constexpr minmax_t(Iter first, Iter last);

private:T min_, max_;

};

constexpr minmax_element

あるイテレータ範囲の

min と

max を保持するクラス

constexpr コンストラクタでは初期化⼦リストにしか

処理を書けない

Page 46: 中3女子でもわかる constexpr

◆コンストラクタで処理を委譲•

Delegating constructor

template<class T>struct minmax_t {

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)

{ }T min_, max_;

};

まず

minmax

を求めてから別のコンストラクタに処理を丸投げ

minmax をmin と

max に振り分け

Page 47: 中3女子でもわかる constexpr

◆コンストラクタで処理を委譲•

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)

{ }T min_, max_;

};

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_;

};

実装⽤クラスに処理を丸投げ

実装⽤クラスで

minmax をmin と

max に振り分け

private 継承

実装⽤クラスのメンバを using

Page 48: 中3女子でもわかる constexpr

◆状態を書き換えるメンバ関数•

constexpr クラス

constexprクラス

struct sha1 {void process_byte(unsigned char byte);template<class Iter>void process_block(Iter first, Iter last);

};

struct sha1 {constexpr sha1 process_byte(unsigned char byte) const;template<class Iter>constexpr sha1 process_block(Iter first, Iter last) const;

};

状態を書き換える↓

「次の状態」を返すように

Page 49: 中3女子でもわかる constexpr

◆状態を書き換えるメンバ関数•

constexpr クラス

constexprクラス

struct random_generator {unsigned int operator()();

};

struct random_generator {constexpr pair<unsigned int, random_generator> operator()() const;

};

状態を書き換え、かつ処理結果を返す

↓処理結果と「次の状態」の

タプルを返す

Page 50: 中3女子でもわかる constexpr

◆constexpr の3⼤コスト•

オブジェクトコピーのコスト

再帰とテンプレートインスタンス化のコ スト

コーディング上のコスト

(⼈間のコスト)

Page 51: 中3女子でもわかる constexpr

◆オブジェクトコピーのコスト•

配列の2つの要素の

swap を考えてみる

constexpr の場合

(元の配列を書換え)

constexpr の場合

(別の配列をつくる)

単なる要素の交換に線形時間

O(n) を要する

⾼々1回のコピーと2回の代⼊

(またはムーヴ)

常に全要素のコピー

Page 52: 中3女子でもわかる constexpr

◆オブジェクトコピーのコスト•

状態を書き換えるメンバ関数の呼出しを考えてみる

状態を書き換えるメンバ関数を

constexpr にすると、 (オブジェクトコピー×呼出し回数)の計算量が余計に かかる

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());

計算量=(計算毎+コピー毎)×要素数

計算量=計算毎×要素数+コピー

Page 53: 中3女子でもわかる constexpr

◆オブジェクトコピーのコスト•

[回避するには]

状態を変更する呼出しは可能な限り少なくする–

(1つの関数で済ませる)

Variadic function や

index_tuple イディオムを活⽤し てオブジェクトコピーが⾏われない処理を書く

Page 54: 中3女子でもわかる constexpr

◆再帰とテンプレート実体化のコスト•

再帰を途中で打ち切るアルゴリズムを考えてみる

template<class T, size_t N, class... Args>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 array<T, N>{{ args... }};

}template<class T, size_t N, class... Args>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)]);}

引数 val と等しい要素があったらそこまでを新しい配列にコピーする

SFINAE の番兵

Page 55: 中3女子でもわかる constexpr

◆再帰とテンプレート実体化のコスト•

再帰を途中で打ち切るアルゴリズムを考えてみる

copied_1

の計算量は

copied_2

と変わらないはず–

ところが、そうはならない

(gcc 4.7)

copied_2

のほうが倍近く遅い

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);

再帰は 5 まで

再帰は 5 まで

要素数が

20

Page 56: 中3女子でもわかる constexpr

◆再帰とテンプレート実体化のコスト•

再帰を途中で打ち切るアルゴリズムを考えてみる

実際に評価される再帰が何回だったとしても(例え0回 でも)SFINAE で打ち切られるまで全てのテンプレート がインスタンス化されるため

(copied_1

10,copied_2

20)

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);

Page 57: 中3女子でもわかる constexpr

◆再帰とテンプレート実体化のコスト•

[回避するには]

インデックスアクセス可能かつ線形探索ならば常に index_tuple イディオムを使う

(再帰のオーバーヘッドも深さ制限もない)

Page 58: 中3女子でもわかる constexpr

◆コーディング上のコスト•

コンパイル時だとまともにデバックできない–

constexpr をマクロにして

on/off オフすれば実⾏時デバッグが

できる

Page 59: 中3女子でもわかる constexpr

◆コーディング上のコスト•

処理フローが増えるたび、別の関数を作って処理を委譲

しなければならない–

ループ処理

⼀時オブジェクトに名前を付ける

Page 60: 中3女子でもわかる constexpr

◆コーディング上のコスト•

例) 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>

t lt T E i t if i t(E i t& T i l T l td f l t )

Page 61: 中3女子でもわかる constexpr

◆コーディング上のコスト• 実装関数が増殖する

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>

t lt T E i t if i t(E i t& T i l T l td f l t )

これは宣⾔だけ書き出して⼀部省略しているので実際のコードはもっと酷い引数コピペの嵐

元々はたった2 個の関数だった

18

個の実装関数

Page 62: 中3女子でもわかる constexpr

◆コーディング上のコスト•

名前付けが酷い

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>

t lt T E i t if i t(E i t& T i l T l td f l t )

generate_uniform_int_true_2_1 とかgenerate_uniform_int_true_2_2 とかgenerate_uniform_int_true_2_3 ...

そもそも意味論でなく単に処理フローで分割しているだけなので、

各関数に意味のある名前を付けるのが難しい

constexpr ラムダ式があれば救われる(かもしれない)

Page 63: 中3女子でもわかる constexpr

◆コーディング上のコスト•

[回避するには]

次期

C++1x に期待する

諦める

Page 64: 中3女子でもわかる constexpr

◆constexpr なライブラリ• 標準ライブラリ• libstdc++ 独⾃拡張• CEL -

ConstExpr Library

• Sprout C++ Library

Page 65: 中3女子でもわかる constexpr

◆標準ライブラリ•

<limits>–

numeric_limits

<utility>–

pair (デフォルトコンストラクタのみ)

<tuple>–

tuple (デフォルトコンストラクタのみ)

<bitset>–

bitset

<memory>–

unique_ptr (デフォルトコンストラクタのみ)–

shared_ptr (デフォルトコンストラクタのみ)–

weak_ptr (デフォルトコンストラクタのみ)–

enable_shared_from_this (デフォルトコンストラクタのみ)

Page 66: 中3女子でもわかる constexpr

◆標準ライブラリ•

<ratio>–

ratio

<chrono>–

各種演算–

duration_values–

duration–

time_point

<string>–

char_traits

<array>–

array (size, max_size, empty のみ)

<iterator>–

istream_iterator (デフォルトコンストラクタのみ)–

istreambuf_iterator (デフォルトコンストラクタのみ)

Page 67: 中3女子でもわかる constexpr

◆標準ライブラリ•

<complex>–

complex

<random>–

各種⽣成器クラス

(min, max のみ)

<regex>–

sub_match (デフォルトコンストラクタのみ)

<atomic>–

atomic (コンストラクタのみ)

<mutex>–

mutex (デフォルトコンストラクタのみ)

Page 68: 中3女子でもわかる constexpr

◆標準ライブラリ• 標準ライブラリの⽅針としては、「通常

の使⽤において、ほぼ⾃明にコンパイル 時処理にできる」ものだけを

constexpr

指定しているようだ– bitset– ratio– chrono など

• numeric_limits が使える⼦になった

• 保守的な⽅針

Page 69: 中3女子でもわかる constexpr

◆libstdc++ 独⾃拡張(GCC 4.7 experimental)

<cmath>–

各種関数

<tuple>–

tuple

<utility>–

forward, move

Page 70: 中3女子でもわかる constexpr

◆libstdc++ 独⾃拡張•

<cmath> が

constexpr 化されてるのが

⼤きい– これに依存する前提なら多くの数学計算の

constexpr 化が楽になる

なんで

<array> が

constexpr じゃない のか……

Page 71: 中3女子でもわかる constexpr

◆CEL -

ConstExpr Library• 作者: RiSK (@sscrisk) さん

– https://github.com/sscrisk/CEL---ConstExpr-Library

<algorithm>•

<numeric>

<cstdlib>•

<cstring>

<iterator>–

各種アルゴリズム

(⾮

Mutating な部分)

Page 72: 中3女子でもわかる constexpr

◆CEL -

ConstExpr Library•

<cctype>– ⽂字列判定

<functional>– 関数オブジェクト

<array>–

array

<utility>–

pair

Page 73: 中3女子でもわかる constexpr

◆CEL -

ConstExpr Library• 標準ライブラリの関数の「シグネチャの

変更なしに

constexpr 化できるもの」を ほぼ⼀通りカバーしている

Page 74: 中3女子でもわかる constexpr

◆Sprout C++ Library•

constexpr ⽂字列

constexpr タプル•

constexpr バリアント

constexpr アルゴリズム•

constexpr 範囲アルゴリズム

constexpr コンテナ操作•

constexpr 乱数

constexpr ハッシュ関数•

constexpr UUID

constexpr 構⽂解析•

constexpr レイトレーシング

Page 75: 中3女子でもわかる constexpr

◆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"

}

Page 76: 中3女子でもわかる constexpr

◆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"

}

型には要素数(最⼤⽂字数)が含まれる

要素数が増える場合:string<N> + string<M>

→ string<N + M>

要素数が減る場合:string<N>::substr

→ string<N>

Page 77: 中3女子でもわかる constexpr

◆constexpr ⽂字列• Sprout.String 実装

• ⽂字列⻑が変わる操作:– 静的に決定できる場合は型レベルで解決– そうでなければ

len を弄って変更

– あるいはユーザ側に最⼤⻑を指定させる

namespace sprout {template<class T, size_t N, Traits = char_traits<T> >class basic_string {

T elems [N + 1];size_t len;

};}

ヌル終端を含めた固定⻑バッファ

⽂字列⻑ (len <= N)

Page 78: 中3女子でもわかる constexpr

◆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

}

配列をソート

配列を反転

Page 79: 中3女子でもわかる constexpr

◆constexpr アルゴリズム• Sprout.Algorithm

– 主に

Mutating sequence operations をカバーする

CEL と合わせれば

STL のアルゴリズムはほぼ全てカ バーできる

• RandomAccessIterator に対しては

index_tuple イ ディオムで効率的に処理する

– ユーザ側で

sprout::next/prev をオーバーロードすることで InputIterator なども渡せる

• それ以外の

IteratorCategory は

Variadic Function で 実装されている

Page 80: 中3女子でもわかる constexpr

◆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";

}

Page 81: 中3女子でもわかる constexpr

◆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";

}

⽇時とファイル名と⾏の ⽂字列からハッシュ値を ⽣成するマクロ

線形合同法エンジン

整数⼀様分布

ランダムシャッフル

Page 82: 中3女子でもわかる constexpr

◆constexpr 乱数• Sprout.Random

– <random> と同じく様々な乱数⽣成器と分布を提供する

関数型⾔語にならって、乱数⽣成器は「⽣成した値」 「次の状態の⽣成器」のペアを返す仕様

コンパイル時に取得できる値でシードに使えるものが __DATA__ __FILE__ __LINE__

くらいしかないので

それを使う

Page 83: 中3女子でもわかる constexpr

◆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);}

Page 84: 中3女子でもわかる constexpr

◆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);}

hex8f

: 8bit16進数にマッチ

Page 85: 中3女子でもわかる constexpr

◆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);}

repeat

: lim<N>回の繰り返しarray<Attr, N * M>

Page 86: 中3女子でもわかる constexpr

◆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);}

>>

: パーサの連結array<Attr, N + M>

Page 87: 中3女子でもわかる constexpr

◆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);}

|

: パーサのORvariant<Attr1, Attr2>

Page 88: 中3女子でもわかる constexpr

◆constexpr 構⽂解析• Sprout.Weed

Boost.Spirit.Qi のような

Expression Template ベースの EDSL 構⽂解析ライブラリ

Expression Template 技法では、処理が細かい単位に 分割されるので、constexpr 化しやすい

constexpr の導⼊によって、コンパイル時⽂字列処理が 相当⼿軽に出来るようになった

おそらく今後

constexpr 正規表現などのライブラリも 出てくると思われる

Page 89: 中3女子でもわかる constexpr

◆constexpr レイトレーシング• Sprout.Darkroom

Page 90: 中3女子でもわかる constexpr

◆constexpr レイトレーシング• Sprout.Darkroom

#include <sprout/darkroom.hpp>#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;

512×512 pixelで作成

Page 91: 中3女子でもわかる constexpr

◆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(

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))

);

オブジェクトの定義(2つの球)

Page 92: 中3女子でもわかる constexpr

◆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<>();

光源の定義(点光源)

カメラレンダラ

レイトレーサー

Page 93: 中3女子でもわかる constexpr

◆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);

ピクセル⽣成

Page 94: 中3女子でもわかる constexpr

◆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) {

std::cout<< unsigned(colors::r(pixel)) << ' '<< unsigned(colors::g(pixel)) << ' '<< unsigned(colors::b(pixel)) << std::endl;

}}

}

標準出⼒へppm 形式で出⼒

Page 95: 中3女子でもわかる constexpr

◆constexpr レイトレーシング• Sprout.Darkroom

metatrace という

TMP ライブラリを元にした

constexpr レイ トレーサーライブラリ

レイトレーシングの基本的なアルゴリズムはとてもシン プル

視点から各ピクセルを通る光線を⾶ばして、ベクトルが オブジェクトと衝突する部分の拡散光と反射光の成分を 得るだけ

Page 96: 中3女子でもわかる constexpr

◆次期

C++1x に期待すること• いくつかのポインタ演算を定数式扱いに

• union の任意のメンバでの初期化を定数式扱いに

p1 < p2;

p1 - p2;

static_cast<int const*>( static_cast<void const*>(p) )

ポインタの⼤⼩⽐較はできない

ポインタ同⼠の減算はできない

void* から他の型への読み替えはできない

union U {X x; Y y;constexpr U() : y() { }

}; 先頭メンバ以外での初期化はできない

Page 97: 中3女子でもわかる constexpr

◆次期

C++1x に期待すること• ラムダ式を定数式扱いに

• new/delete を定数式に出来るように

• 標準ライブラリを更に

constexpr 化

template<class F>constexpr auto call(F f) -> decltype(f()) { return f(); }

call( []{ return 0; } );

constexpr 関数にラムダ式を渡せない

Page 98: 中3女子でもわかる constexpr

◆constexpr 化できそうなもの• 正規表現

– Regex / Expressive• 汎⽤

Expression Template

– Proto• シリアライズ

– Serialization• 画像処理

– GIL• 数学関数

– Math.SpecialFunction• etc...

Page 99: 中3女子でもわかる constexpr

◆まとめ•

constexpr で表現可能な応⽤範囲はとて

も広い•

コーディング上の制約と落とし⽳は多い

ので気をつける•

数値計算が得意分野

constexpr で遊ぼう!

Page 100: 中3女子でもわかる constexpr

ご静聴ありがとう ございました