constexpr 中3女子テクニック

138
constexpr中3女子テクニック ―実践と濫⽤そしてC++14へ Boost.勉強会 #12 bolero_MURAKAMI 2013/6/22

Upload: genya-murakami

Post on 10-Jun-2015

13.390 views

Category:

Documents


4 download

TRANSCRIPT

Page 1: Constexpr 中3女子テクニック

constexpr中3女子テクニック ―実践と濫⽤そしてC++14へ

Boost.勉強会

#12bolero_MURAKAMI2013/6/22

Page 2: Constexpr 中3女子テクニック

◆自己紹介•

名前

:

村上

原野

(むらかみ

げんや)

@bolero_MURAKAMI, id:boleros

棲息地:

大都会岡山

仕事

:

猪風来美術館陶芸指導員・普段はろくろをまわしたり、

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

constexpr

です

Page 3: Constexpr 中3女子テクニック

◆自己紹介•

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

Sprout C++ Library (constexpr

ライブラリ)github.com/bolero-MURAKAMI/Sprout

前回発表資料:Boost.勉強会

#7

【中3⼥⼦でもわかる

constexpr】Boost.勉強会

#8

【中3⼥⼦が狂える本当に気持ちのいい

constexpr】www.slideshare.net/GenyaMurakami

Page 4: Constexpr 中3女子テクニック

◆アジェンダ•

はじめに

いまさら聞けない

constexpr

入門•

逆引き

constexpr

マニュアル

constexpr

アルゴリズム実装テクニック•

これからの

constexpr

の話

まとめ

Page 5: Constexpr 中3女子テクニック

◆いまさら聞けない

constexpr

入門

constexpr

とは•

constexpr

を使うべき

5 の理由

constexpr

の落とし⽳

Page 6: Constexpr 中3女子テクニック

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

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

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

実⾏時の世界(人間界)

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

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

メタプログラミング

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

実⾏時オブジェクト

定数式

通常のプログラミング

C++03

Page 7: Constexpr 中3女子テクニック

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

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

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

実⾏時の世界(人間界)

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

constexpr

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

メタプログラミング

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

実⾏時オブジェクト

定数式

通常のプログラミング

C++11

Page 8: Constexpr 中3女子テクニック

◆constexpr

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

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

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

[算術型]

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

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

[ポインタ型]

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

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

[列挙型] enum

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

Page 9: Constexpr 中3女子テクニック

◆constexpr

を使うべき

5 の理由• 明示的なコンパイル時定数の定義• コンパイル時定数を返す関数• 副作⽤がないことを保証する• better TMP• 初期化をあらかじめ⾏っておく

Page 10: Constexpr 中3女子テクニック

◆明示的なコンパイル時定数の定義• 定数だがコンパイル時定数ではない例

– ill-formed !!!

struct X { int n; };

const X x = { 10 };int a[x.n] = { 1 };

配列の宣⾔にはコンパイル時定数が必要

Page 11: Constexpr 中3女子テクニック

◆明示的なコンパイル時定数の定義• constexpr

で、実⾏時定数ではなくコンパイル時定数で

あることを明示するstruct X { int n; };

constexpr X x = { 10 };int a[x.n] = { 1 };

OK! コンパイル時定数

Page 12: Constexpr 中3女子テクニック

◆コンパイル時定数を返す関数• コンパイル時に定まる値だがコンパイル時定数として使

えない例template<class T, size_t N>struct MyArray {

T elem[N];size_t size() const { return N; }

};

N はコンパイル時定数だが、 size() はコンパイル時定数でない

Page 13: Constexpr 中3女子テクニック

◆コンパイル時定数を返す関数• constexpr

で、関数をコンパイル時定数として使えるよ

うにするtemplate<class T, size_t N>struct MyArray {

T elem[N];constexpr size_t size() const { return N; }

};

OK! コンパイル時定数

Page 14: Constexpr 中3女子テクニック

◆副作⽤がないことを保証する• 副作⽤があるか無いか分からない例

int x = format();

C:ドライブをフォーマットする副作⽤がある かもしれない

Page 15: Constexpr 中3女子テクニック

◆副作⽤がないことを保証する• 副作⽤が確実にない例

constexpr int x = format();

C:ドライブをフォーマットするとしても、 その前にコンパイルエラーになる

Page 16: Constexpr 中3女子テクニック

◆better TMP• 煩雑なテンプレートメタプログラミング

typedef boost::mpl::vector_c<int, 1, 2, 3, 4, 5> src;typedef typename boost::mpl::accumulate<

src,boost::mpl::int_<0>,boost::mpl::plus<boost::mpl::_1, boost::mpl::_2>

>::type accumulated;

Page 17: Constexpr 中3女子テクニック

◆better TMP• ⾒慣れたプログラムと変わらない

constexpr

constexpr auto src = make_array<int>( 1, 2, 3, 4, 5 );constexpr auto accumulated =

range::accumulate(src, 0, plus<>() );

Page 18: Constexpr 中3女子テクニック

◆初期化をあらかじめ⾏っておく• コンパイル時三角関数テーブル

using namespace sprout::adaptors;constexpr array<double, 90> degree_sin_table

= sinusoidal( 1. / 360 ) | copied;

浮動小数点数のコンパイル時計算が出来るの は constexpr だけ

Page 19: Constexpr 中3女子テクニック

◆初期化をあらかじめ⾏っておく• constant initialization

– あらゆる動的初期化より先に⾏われるため、ありがちな静的変 数の初期化順序への依存や競合が起こらない

static std::mutex m; // 普通のグローバル変数

constexpr コンストラクタを持つ型

Page 20: Constexpr 中3女子テクニック

◆constexpr

の落とし⽳• 定数式だけど定数じゃない• 実は副作⽤を禁止できない

Page 21: Constexpr 中3女子テクニック

◆定数式だけど定数じゃない• すごく

const っぽいシグネチャ

constexpr int const& f( int const& t );

Page 22: Constexpr 中3女子テクニック

◆定数式だけど定数じゃない• すごく

const っぽくないシグネチャにしてみる

constexpr int& f( int& t );

完全に合法

Page 23: Constexpr 中3女子テクニック

◆定数式だけど定数じゃない• const_cast で

const 外しをしてみる

constexpr int& f( int const& t ) {return const_cast<int&>(t);

}

完全に合法

Page 24: Constexpr 中3女子テクニック

◆定数式だけど定数じゃない• constexpr 指定の変数が暗黙の

const 修飾されるだけ

で、constexpr 関数の引数や返値の

const 性とは何も 関わりがない

• たとえコンパイル時の定数式評価であっても、非

const rvalue/lvalue 参照などの、あらゆる

value category

の式が扱われる

Page 25: Constexpr 中3女子テクニック

◆実は副作⽤を禁止できない• 人生、宇宙、すべての答えを代入するだけの関数

template<class T>T& f( T&& t ) { return t = 42; }

もちろん副作⽤がある

Page 26: Constexpr 中3女子テクニック

◆実は副作⽤を禁止できない• これもそのまま

constexpr 関数に出来る

template<class T>constexpr T& f( T&& t ) { return t = 42; }

Page 27: Constexpr 中3女子テクニック

◆実は副作⽤を禁止できない• これもそのまま

constexpr 関数に出来る

template<class T>constexpr T& f( T&& t ) { return t = 42; }

constexpr int k = f(0);

もちろんコンパイル時に評価しよう とするとエラーになるが……

int i = 0;int j = f( i );

実⾏時評価だと何も問題なく コンパイル・実⾏できる

Page 28: Constexpr 中3女子テクニック

◆実は副作⽤を禁止できない• 引数によって副作⽤があったり無かったりする場合

template<class T>constexpr T& f( T&& t, bool cond ) { return cond ? t : (t = 42); }

constexpr int k = f( 0, true ); /* 副作用なし */int i = 0;int j = f( i, false ); /* 副作用あり */

Page 29: Constexpr 中3女子テクニック

◆実は副作⽤を禁止できない• constexpr 関数が副作⽤について保証するのは以下の場

合しかない– コンパイル時に呼び出されたとき、副作⽤があればコンパイル

エラーになる– コンパイル時に呼び出せる(副作⽤がない)とき、実⾏時にそれ

と等値な引数で呼び出しても、同じく副作⽤がない

• 実⾏時の

constexpr 関数呼び出しで、副作⽤がないこ とを証明するには以下の場合しかない

– コンパイル時に等値な引数で呼び出して、エラーにならないこ とを確認する

– 実装を⾒て、全ての実⾏パスで副作⽤が起こりえないことを検 証する

Page 30: Constexpr 中3女子テクニック

◆実は副作⽤を禁止できない• constexpr 関数はコンパイル時にも実⾏時にも呼び出せ

るが、実⾏時に副作⽤がないことはまったく保証しない

• constexpr 指定の有無が、ドキュメントレベルの目安に はなる

Page 31: Constexpr 中3女子テクニック

◆逆引き

constexpr

マニュアル•

constexpr

で文字列を扱いたい

constexpr

で配列(コンテナ)を扱いたい•

constexpr

でタプルを扱いたい

constexpr

でアルゴリズムを使いたい•

constexpr

RangeAdaptor

を使いたい

constexpr

でアサーションを使いたい•

constexpr

で数学関数を使いたい

constexpr

で乱数を使いたい•

constexpr

でハッシュ関数を使いたい

constexpr

UUID を使いたい•

constexpr

で構文解析したい

constexpr

でレイトレーシングしたい•

constexpr

で波形編集したい

Page 32: Constexpr 中3女子テクニック

◆文字列を扱いたい• それ

Sprout.String

で出来るよ!

• リテラルから文字列クラスへ

• 文字列連結

• std::string

互換のインタフェース

#include <sprout/string.hpp>

constexpr auto s = to_string( "Hello world!" );// -> string<12> :型には要素数(最大文字数)が含まれる

constexpr auto s = to_string( "Hello" ) + to_string( "world!" );// string<5> + string<7> -> string<12>

constexpr auto pos = s.find( "o wo" ); // 4constexpr auto s2 = s.substr( 0, pos ); // "Hell"

Page 33: Constexpr 中3女子テクニック

◆文字列を扱いたい• 文字列→算術型の変換

• 算術型→文字列の変換

• その他、辞書順⽐較やストリーム入出⼒

etc...

constexpr auto istr = to_string( 37564 ); // "37564"constexpr auto dstr = to_string( 3.141592 ); // "3.141592"

constexpr auto i = stoi( to_string( "37564" ) ); // 37564constexpr auto d = stod( to_string( "3.141592" ) ); // 3.141592

Page 34: Constexpr 中3女子テクニック

◆文字列を扱いたい• 所有権を持たない文字列クラス

– (C++1y の

std::string_view

互換)#include <sprout/utility/string_view.hpp>

constexpr auto s = string_view( "Hello world!" );// -> string_view :型には要素数を含まない

Page 35: Constexpr 中3女子テクニック

◆配列(コンテナ)を扱いたい• それ

Sprout.Array

で出来るよ!

• 配列の作成

• std::array

互換のインタフェース

• constexpr

なイテレータ

#include <sprout/array.hpp>

constexpr auto a = make_array<int>( 1, 2, 3, 4, 5 );// -> array<int, 5>

constexpr auto auto size = a.size(); // 5constexpr auto i2 = a[2]; // 3constexpr auto i5 = a.at(5); // error: out_of_range

constexpr auto first = a.begin();constexpr auto last = a.end();

Page 36: Constexpr 中3女子テクニック

◆タプルを扱いたい• それ

Sprout.Tuple

で出来るよ!

• タプルの作成

• std::tuple

互換のインタフェース

• ファンクタを呼ぶ

#include <sprout/tuple.hpp>

constexpr auto t = make_tuple( 10, 3.14, to_string( "Foo" ) );// -> tuple<int, double, string<3>>

constexpr auto t = make_tuple( 10, 3.14 );constexpr auto f = make_fused( plus<>() );constexpr auto result = f(t); // call: 10 + 3.14

constexpr auto size = tuple_size<decltype(t)>::value; // 3constexpr auto i1 = get<1>(t); // 3.14

Page 37: Constexpr 中3女子テクニック

◆アルゴリズムを使いたい• それ

Sprout.Algorithm

で出来るよ!

• 変更を伴わないアルゴリズム– (STL アルゴリズム互換)

#include <sprout/algorithm.hpp>

constexpr auto a = make_array<int>( 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 );static_assert(

is_sorted( a.begin(), a.end() ),"ソートされているか" );

static_assert(all_of( a.begin(), a.end(), bind2nd( modulus<>(), 2 ) ),"奇数であるか" );

Page 38: Constexpr 中3女子テクニック

◆アルゴリズムを使いたい• 変更を伴うアルゴリズム

• 変更を伴うアルゴリズムの

STL との違い– 出⼒イテレータを取るアルゴリズムは、代わりに出⼒コンテナ

を受け取って結果を返す

– 入出⼒イテレータのペアを取るアルゴリズムは、代わりに入出 ⼒コンテナを受け取って結果を返す

constexpr auto a = make_array<int>( 5, 1, 9, 4, 8, 2, 7, 3, 10, 6 );constexpr auto sorted = sort( a ); // 1 2 3 4 5 6 7 8 9 10constexpr auto reversed = reverse( sorted ); // 10 9 8 7 6 5 4 3 2 1

std::reverse_copy( first, last, out ); // ↓constexpr auto reversed = reverse_copy( first, last, container );

std::reverse( first, last ); // ↓constexpr auto reversed = reverse( container );

Page 39: Constexpr 中3女子テクニック

◆アルゴリズムを使いたい• Range 版アルゴリズムもあるよ!

#include <sprout/range/algorithm.hpp>

constexpr auto a = make_array<int>( 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 );static_assert(

is_sorted( a ),"ソートされているか" );

static_assert(all_of( a, bind2nd( modulus<>(), 2 ) ),"奇数であるか" );

Page 40: Constexpr 中3女子テクニック

◆RangeAdaptor

を使いたい• それ

Sprout.Range.Adaptor

で出来るよ!

• 様々なアダプタをパイプ演算⼦で繋げる

• Haskell で書くと

#include <sprout/range/adaptor.hpp>

using namespace sprout::adaptor;constexpr array<int, 10> a =

counting( 1 ) // [1..] の無限リスト| transformed( bind2nd( multiplies<>(), 2 ) ) // 全要素に (* 2) 適用| taken( 5 ) // 5 要素を取り出し| jointed( adaptor::counting( 11 ) ) // [11..] をリスト連結| copied // 任意のコンテナへ変換可能にする;

// 2 4 6 8 10 11 12 13 14 15

(++ [11..]) $ take 5 $ map (* 2) [1..]

Page 41: Constexpr 中3女子テクニック

◆RangeAdaptor

を使いたい• RangeAdaptor

の特⻑

– 遅延評価が出来る– 一時オブジェクトの生成を最小限に出来る– アダプタの適⽤が副作⽤を持たない– constexpr

に向いている!

Page 42: Constexpr 中3女子テクニック

◆アサーションを使いたい• それ

Sprout.Assert

で出来るよ!

• コンパイル時でも実⾏時でも使えるアサート

• コンパイル時の場合→コンパイルエラー

(GCC)

• 実⾏時の場合→標準の

assert と同じ

(GCC)

#include <sprout/assert.hpp>

template<typename T>constexpr T div(T num, T denom) {

return SPROUT_ASSERT(denom != 0), (num / denom);}

div(3.14, 0.0);

Page 43: Constexpr 中3女子テクニック

◆アサーションを使いたい• コンパイル時の場合→コンパイルエラー

(GCC)

• 実⾏時の場合→標準の

assert と同じ

(GCC)

in constexpr expansion of ‘sprout::detail::assertion_check((denom != 0.0), ((const char*)"***** Internal Program Error - assertion (denom != 0) failed: a.cpp(6)"))’

***** Internal Program Error - assertion (denom != 0) failed: a.cpp(6)

Page 44: Constexpr 中3女子テクニック

◆数学関数を使いたい• それ

Sprout.Math

で出来るよ!

• <cmath> の殆どの数学関数をサポート

• GCC のビルトイン関数が使える環境ならより高速に

#include <sprout/math.hpp>

constexpr auto v1 = cos(0.5); // 三角関数constexpr auto v2 = tgamma(3.0); // ガンマ関数

Page 45: Constexpr 中3女子テクニック

◆乱数を使いたい• それ

Sprout.Random

で出来るよ!

• 乱数種

• いくつかの疑似乱数生成エンジン

• いくつかの分布クラス

#include <sprout/random.hpp>

constexpr auto rng1 = minstd_rand0( seed ); // 線形合同法エンジンconstexpr auto rng2 = taus88( seed ); // 結合トーズワース法エンジン

constexpr std::size_t seed = SPROUT_UNIQUE_SEED;// コンパイル日時、ファイル名、行数を利用

constexpr auto dist1 = uniform_int_distribution<>( 1, 6 ); // 整数一様分布constexpr auto dist2 = normal_distribution<>( 5, 2 ); // 正規分布

Page 46: Constexpr 中3女子テクニック

◆乱数を使いたい• 返値は

{ 生成値, 次の状態の生成器

} のペアになる

• 乱数列を

ForwardTraversalRange

として扱う

constexpr auto rnd = dist(rng); // 乱数生成constexpr auto val = rnd.generated_value(); // 生成値constexpr auto gen = rnd.next_generator(); // 次の生成器

constexpr auto seq = random::make_range( rng, dist ); // 乱数列constexpr array<int, 10> a = seq | adaptor::copied;

Page 47: Constexpr 中3女子テクニック

◆ハッシュ関数を使いたい• それ

Sprout.Functional.Hash

で出来るよ!

• std::hash

互換のインタフェース#include <sprout/functional/hash.hpp>

constexpr std::size_t h = hash<double>( 3.14 );

Page 48: Constexpr 中3女子テクニック

◆ハッシュ関数を使いたい• Sprout.Checksum

でハッシュアルゴリズムも使える

よ!

• MD5 や

SHA1 のハッシュ関数

• メソッドチェインでソースを流し込む

#include <sprout/checksum.hpp>

constexpr auto md5_hash = md5().process_range( to_string( "foobar" ) )();constexpr auto sha1_hash = sha1().process_range( to_string( "foobar" ) )();

Page 49: Constexpr 中3女子テクニック

◆UUID を使いたい• それ

Sprout.Uuid

で出来るよ!

• boost::uuids::uuid

互換のインタフェース#include <sprout/uuid.hpp>

Page 50: Constexpr 中3女子テクニック

◆UUID を使いたい• 文字列から

UUID 生成

• ランダムな

UUIDv4 生成

• MD5/SHA1 による

UUIDv3/v5 生成

constexpr auto id = uuids::make_uuid(to_string( "{550e8400-e29b-41d4-a716-446655440000}" ) );

// 文字列と同じ

UUID

constexpr auto id = uuids::make_uuid4( SPROUT_UNIQUE_SEED );// 任意の乱数種または乱数生成器による UUIDv4

constexpr auto id = uuids::make_uuid5_dns( to_string( "boost.org" ) );// DNS 名前空間の SHA1 による

UUIDv5

Page 51: Constexpr 中3女子テクニック

◆UUID を使いたい• UUID ユーザ定義リテラル

constexpr auto id3 = "{550e8400-e29b-41d4-a716-446655440000}"_uuid;constexpr auto id5 = "DNS"_uuid5( to_string( "boost.org" ) );

Page 52: Constexpr 中3女子テクニック

◆構文解析したい• そうだね、Sprout.Weed

だね!!

• 例)C++の識別⼦(予約済み識別⼦を除く)にマッチする パーザを作成する

#include <sprout/weed.hpp>

constexpr auto identifier_p =!( '_' >> char_( "A-Z“ ) ) // アンダースコア+大文字で始まらない>> char_( "a-zA-Z_“ ) // 英字またはアンダースコアで始まる>> *lim<15>( char_( "0-9a-zA-Z_“ ) - "__“ )

// ゼロ個以上の英数字またはアンダースコア(アンダースコアは連続しない);

Page 53: Constexpr 中3女子テクニック

◆構文解析したい• パーザの適⽤

constexpr auto s1 = to_string( "_foobar" );static_assert( parse_range( s1, identifier_p ).current() == s1.end(),

"マッチする" );

constexpr auto s2 = to_string( "_Foobar" );static_assert( parse_range( s2, identifier_p ).current() != s2.end(),

"マッチしない" );

constexpr auto s3 = to_string( "foo__bar" );static_assert( parse_range( s3, identifier_p ).current() != s3.end(),

"マッチしない" );

Page 54: Constexpr 中3女子テクニック

◆レイトレーシングしたい• 中3⼥⼦のマストアイテム

Sprout.Darkroom

#include <sprout/darkroom.hpp>

Page 55: Constexpr 中3女子テクニック

◆レイトレーシングしたい• 鏡面や複数光源の設定

Page 56: Constexpr 中3女子テクニック

◆レイトレーシングしたい• 合わせ鏡のような再帰的追跡

Page 57: Constexpr 中3女子テクニック

◆レイトレーシングしたい• テクスチャファイルの読み込み・貼り付け

Page 58: Constexpr 中3女子テクニック

◆波形編集したい• ナウなヤングにバカウケ

Sprout.Compost

• 単純な正弦波の生成#include <sprout/compost.hpp>

using namespace sprout::compost;constexpr array<complex<double>, 256> src =

waves::sinusoidal( 10. / 256, 10000. ) | ranges::copied;

Page 59: Constexpr 中3女子テクニック

◆波形編集したい• DFT (離散フーリエ変換)

constexpr auto trans = src | analyses::dft | ranges::copied;// 離散フーリエ変換

constexpr auto spec =trans | analyses::amplitude_spectrum | ranges::copied;

// 振幅スペクトルに変換

Page 60: Constexpr 中3女子テクニック

◆波形編集したい• 単音の正弦波を生成

– 再生:sine_sound.wav

using namespace sprout::compost;constexpr array<std::int16_t, size> wav =

waves::sinusoidal( // 指定音階の正弦波を生成equal_temperament_value( semitones ) * base / sample_per_sec, 0.8 )

| formats::as_pcm_wave16 // 16bitWAVE に変換| ranges::copied // 任意のコンテナに変換可能にする;

Page 61: Constexpr 中3女子テクニック

◆波形編集したい• モーツァルトのきらきら星変奏曲ハ⻑調K. 265の最初の

部分のメロディを生成

– 再生:sine_twinkle.wav

Page 62: Constexpr 中3女子テクニック

◆波形編集したい• 外部ファイルから波形データの読み込み

– 再生:sound.wav

#define COMPOST_DEF_LOAD_SOURCE_IDENTIFIER wav#define COMPOST_DEF_LOAD_INFO_IDENTIFIER wav_info#define COMPOST_DEF_LOAD_SOURCE_FILE FILENAME#include COMPOST_LOAD_SOURCE

Page 63: Constexpr 中3女子テクニック

◆波形編集したい• ディストーションをかける

– 再生:distortion.wav

constexpr sprout::array<std::int16_t, size> wav_data =wav.elements()| effects::distorted( 100., 0.5 ) // ディストーション| formats::as_pcm_wave16 // 16bitWAVE に変換| ranges::copied // 任意のコンテナに変換可能にする;

Page 64: Constexpr 中3女子テクニック

◆波形編集したい• 音声合成したい

– Rosenberg 波を音源波形とする(τ1 = 0.8, τ2 = 0.16)

– フォルマント(音声のスペクトルに固有のピーク)を⽤意する– IIR フィルタ(無限インパルス応答において特定の周波数成分を

取り出す)でレゾナンスを掛ける

– 再生:vowel.wav

Page 65: Constexpr 中3女子テクニック

◆constexpr

アルゴリズム実装テクニック

再帰深度を抑える•

アルゴリズム

クラス設計•

その他

Page 66: Constexpr 中3女子テクニック

◆再帰深度を抑える•

再帰深度を抑える意義

IndexTuple

イディオム•

倍分再帰

Page 67: Constexpr 中3女子テクニック

◆再帰深度を抑える意義• constexpr

関数においてループは再帰で実装できるが、

その深度は実装によって制限される

• 規格が実装に推奨する

constexpr

関数の再帰深度

512– 数千要素の配列を、線形再帰でループするとすぐ制限を超える– ちなみにテンプレートインスタンス化の再帰深度

1024

Page 68: Constexpr 中3女子テクニック

◆再帰深度を抑える意義• 重要なのは計算量(オーダー)

– 線形オーダー

Ο(n)

だと厳しい– 対数オーダー

Ο(log

n)

だとかなり良い(例えば要素数

16→256

でも再帰数

4→8 )– 定数オーダー

Ο(1)

なら最高(要素数が増えても変わらない)

Page 69: Constexpr 中3女子テクニック

◆IndexTuple

イディオム• IndexTuple

イディオムで

reverse の実装

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 make_index_tuple<N>::type() );}

Page 70: Constexpr 中3女子テクニック

◆IndexTuple

イディオム• IndexTupe

イディオムで

reverse の実装

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 make_index_tuple<N>::type() );}

インデックス列のパラメータパック

パック展開式

Page 71: Constexpr 中3女子テクニック

◆IndexTuple

イディオム• 原理

– 型レベルで

[0..N)

のインデックス列を⽤意(テンプレートパラ メータパック)

– 要素列

a[0], a[1], ...,

a[N-1]

に展開(パック展開式)

• 数学的意味– 簡単に⾔えば自然数列

{0, 1, ...,

N-1} から

S への写像

a:{0, 1, ...,

N-1} →

S を定義すること– reverse の場合は、入⼒を

A とすると一般項

a[n] = A[N-1-n]

になる

Page 72: Constexpr 中3女子テクニック

◆IndexTuple

イディオム• 適⽤できる条件

– 入⼒が

RandomAccessTraversal

である(添字アクセス可能)– 一般項の計算量がほぼ定数時間である– 漸化式(例えばフィボナッチ数)などは一般に項

a[n] の計算量が

Ο(n) になるので適⽤できない– n 番目の素数は一意に定まるが、n 番目の素数を定数時間で求

める方法はないので適⽤できない

• 計算量– 再帰深度は定数オーダー

Ο(1)

– ただし、テンプレートインスタンス化の再帰深度が高々対数 オーダー

Ο(log

n)

Page 73: Constexpr 中3女子テクニック

◆IndexTuple

イディオム• ライブラリ

– C++14 の

integer_sequence• N3658

の提案では、Efficiency considerations として計算量

Ο(log2 n) の実装について考察– Sprout の

index_tuple

• integer_sequence

とほぼ互換のインタフェース• 様々なユーティリティ• 計算量

log2(n) の保証

Page 74: Constexpr 中3女子テクニック

◆倍分再帰• 倍分再帰で

distance の実装

template<typename InputIterator>constexpr pair<InputIterator, typename iterator_traits<InputIterator>::difference_type>distance_impl_1(

pair<InputIterator, typename iterator_traits<InputIterator>::difference_type> const& current,InputIterator last, typename iterator_traits<InputIterator>::difference_type n)

{typedef pair<InputIterator, typename iterator_traits<InputIterator>::difference_type> type;return current.first == last ? current

: n == 1 ? type(next(current.first), current.second + 1): distance_impl_1(

distance_impl_1(current,last, n / 2 /* 左側を検索 */),

last, n - n / 2 /* 右側を検索 */)

;}

Page 75: Constexpr 中3女子テクニック

◆倍分再帰• 倍分再帰で

distance の実装

template<typename InputIterator>constexpr pair<InputIterator, typename iterator_traits<InputIterator>::difference_type>distance_impl(

pair<InputIterator, typename iterator_traits<InputIterator>::difference_type> const& current,InputIterator last, typename iterator_traits<InputIterator>::difference_type n)

{typedef pair<InputIterator, typename iterator_traits<InputIterator>::difference_type> type;return current.first == last ? current

: distance_impl(distance_impl_1(

current,last, n /* 検索範囲 n を検索 */),

last, n * 2 /* 次の検索範囲 n * 2 を検索 */)

;}

Page 76: Constexpr 中3女子テクニック

◆倍分再帰• 倍分再帰で

distance の実装

template<typename InputIterator>constexpr typename iterator_traits<InputIterator>::difference_typedistance(InputIterator first, InputIterator last) {

typedef pair<InputIterator, typename iterator_traits<InputIterator>::difference_type> type;return distance_impl(type(first, 0), last, 1).second;

}

Page 77: Constexpr 中3女子テクニック

◆倍分再帰• 原理

– サイクル

1 :与えられた範囲を⼆分検索する– サイクル

2 :試⾏範囲を倍々しながらサイクル

1 を呼ぶ

Page 78: Constexpr 中3女子テクニック

◆倍分再帰• 基本的には⼆分検索(サイクル

1)

• ただし、範囲が未知なので試⾏範囲を指数的に増やして いく(サイクル

2)

– 現在の範囲で終了しなかったら、右側に同じだけ拡張

• サイクル

1 は

Ο(log n)、サイクル

2 も

Ο(log n)

なの で、合わせた計算量も

Ο(log n)

になる

• 試⾏範囲を「⼆倍→⼆分」繰り返すので、「倍分再帰」 と名付けた(造語)

Page 79: Constexpr 中3女子テクニック

◆倍分再帰• 適⽤できる条件

– 入⼒が

SinglePassTraversal

以上である

• 計算量– 再帰深度はほぼ対数オーダー

Ο(log2 n)

– ただしイテレータ同士の⽐較回数が最大で

Ο(2^ceil(log2 n))• STL で同等のアルゴリズムだと

Ο(n)

• n が

2 の冪乗の場合は同じ計算量だが、それ以外だと若⼲非効率

Page 80: Constexpr 中3女子テクニック

◆アルゴリズム• 変更を伴わないアルゴリズム• 変更を伴うアルゴリズム• RangeAdaptor

Page 81: Constexpr 中3女子テクニック

◆変更を伴わないアルゴリズム• <algorithm> や

<numeric> の

Non-modifying

sequence operations– all_of, find

など

• <cstring>– strlen, strcmp

など

• インタフェース– 標準ライブラリとほぼ同じにできる

Page 82: Constexpr 中3女子テクニック

◆変更を伴わないアルゴリズム• 処理をディスパッチ

– 入⼒が

RandomAccessTraversal

である• →

単純な⼆分検索

– それ以外• →

倍分再帰

• 計算量– 入⼒が一つの範囲の場合

Ο(log2 n)

– 入⼒が⼆つの範囲の場合

Ο(log2 n+m)– 標準ライブラリとほぼ同じ効率で実装できる

Page 83: Constexpr 中3女子テクニック

◆変更を伴うアルゴリズム• <algorithm> や

<numeric> の

Mutating sequence

operations– reverse, transform, sort

など

• インタフェース– 出⼒をコンテナにコピーして返すような、副作⽤のない形にす

る必要があるvoid sort( Iterator first, Iterator last );// 副作用がある

constexpr Container sort( Container const& cont );// 副作用がない

Page 84: Constexpr 中3女子テクニック

◆変更を伴うアルゴリズム• 出⼒が添字に対して一意に定義できる場合

– reverse

など– 入⼒が

RandomAccessTraversal

である

• →

IndexTuple

イディオム– それ以外

• →

愚直に線形再帰

• 出⼒が添字に対して一意に定義できない場合– sort

など

– 愚直に線形再帰

Page 85: Constexpr 中3女子テクニック

◆変更を伴うアルゴリズム• 計算量

– IndexTuple

イディオムが使える場合• →

Ο(n)

– それ以外• →

アルゴリズムによる

• 問題点– クイックソートなど

In-place アルゴリズムが使えない

– 出⼒を常にコピーするため、オブジェクトコピーの計算量が Ο(n) 余計に必要

Page 86: Constexpr 中3女子テクニック

◆RangeAdaptor• Boost.Range

Pstade.Oven

の実装が典型的

• RangeAdaptor

の適⽤自体は通常副作⽤を持たず、最終 的に評価される時点で実処理が⾏われる

Page 87: Constexpr 中3女子テクニック

◆RangeAdaptor• C++ における

Range は、しばしば

[first, last)

といっ

たイテレータを組にしたクラスとして表現される– Range のクラスそのものは状態を変更しないことが多い– D ⾔語の

Range では、イテレータではなく

Range そのものが

状態を持っている

struct MyRange {constexpr iterator begin() const;constexpr iterator end() const;

};

Page 88: Constexpr 中3女子テクニック

◆RangeAdaptor• 要素コピー回数の⽐較• 通常のアルゴリズムの場合

– コピー回数

= 10 ×

3

• RangeAdaptor

の場合

– コピー回数

= 10

constexpr auto a1 = iota<array<int, 10>>( 1 ); // 10回constexpr auto a2 = reverse( a1 ); // 10回constexpr auto a = range::transform(

a2, a2, bind2nd( multiplies<>(), 2 ) ); // 10回

constexpr array<int, 10> a =counting( 1, 10 )| reversed| transformed( bind2nd( multiplies<>(), 2 ) )| copied;

Page 89: Constexpr 中3女子テクニック

◆RangeAdaptor• reversed アダプタの実装例

template<class BaseRange>class reversed_range {

constexpr reverse_iterator begin() const;constexpr reverse_iterator end() const;

};class reversed_forwarder {};static constexpr reversed_forwarder reversed = {};

template<class BaseRange>constexpr reversed_range<BaseRange>operator| ( BaseRange const& rng, reversed_forwarder ) {

return reversed_range<BaseRange>( rng );}

Page 90: Constexpr 中3女子テクニック

◆RangeAdaptor• reversed アダプタの実装例

template<class BaseRange>class reversed_range {

constexpr reverse_iterator begin() const;constexpr reverse_iterator end() const;

};class reversed_forwarder {};static constexpr reversed_forwarder reversed = {};

template<class BaseRange>constexpr reversed_range<BaseRange>operator| ( BaseRange const& rng, reversed_forwarder ) {

return reversed_range<BaseRange>( rng );}

reversed 自体は機能を持たず、 operator|() を ADL で呼ぶ為

のタグとして使われる

reversed_range は、範囲 を逆順に辿るイテレータ を保持する

operator|() によって、 reversed_range を生成 して返す

Page 91: Constexpr 中3女子テクニック

◆RangeAdaptor• 目的の動作をするイテレータさえ実装できれば、

RangeAdaptor

も簡単に実装できる

Page 92: Constexpr 中3女子テクニック

◆クラス設計• イテレータインタフェース• データメンバアクセス• メソッドチェイン

Page 93: Constexpr 中3女子テクニック

◆イテレータインタフェース• 通常副作⽤を持たない

– デリファレンス:

*a– 添字デリファレンス:

a[n]

– 加算/減算:

a + n, a -

n, a -

b– 等価⽐較:

a == b, a != b

– 不等価⽐較:

a < b, a > b, a <= b, a >= b

• 通常副作⽤を持つ– インクリメント/デクリメント:

++a, --a, a++, a--

– 加算代入/減算代入:

a += n, a -= n

Page 94: Constexpr 中3女子テクニック

◆イテレータインタフェース• 案

1 :++/--

の代わりにメンバ関数

next/prev

を持た

せる

– 欠点:同じメンバ関数を持っていない、他の全てのイテレータ を統一的に扱えない

struct MyIterator {constexpr MyIterator next() const;constexpr MyIterator prev() const;

};

Page 95: Constexpr 中3女子テクニック

◆イテレータインタフェース• 案 2 :フリー関数

iterator_next/iterator_prev

をADL

でルックアップ

– 利点:他のライブラリのイテレータでもアダプトすることがで きる

– 欠点:邪悪な

ADL

に依存する– 名前を

next/prev

にしない理由は、一般的すぎる名前だと

ADL

で余計なものまで候補になるおそれがある為

• Sprout では案

2 を採⽤している

constexpr MyIterator iterator_next(MyIterator);constexpr MyIterator iterator_prev(MyIterator);

Page 96: Constexpr 中3女子テクニック

◆イテレータインタフェース• 挙動をフォールバックする汎⽤

next フリー関数

– ADL で

iterator_next(a) が呼べるか• →

iterator_next(a)

– a が

RandomAccessIterator

かつリテラル型か• →

it + 1

– それ以外• →

std::next(a)

template<class ForwardIterator>constexpr ForwardIterator next(ForwardIterator it);

Page 97: Constexpr 中3女子テクニック

◆データメンバアクセス• 通常のメンバ関数では、データメンバアクセスを完全に

代替することは出来ない

Page 98: Constexpr 中3女子テクニック

◆データメンバアクセス• 公開されたデータメンバの場合

template<class T>struct Holder {

T value;};

constexpr int i = Holder<int>{ 100 }.value; // データメンバを参照

Page 99: Constexpr 中3女子テクニック

◆データメンバアクセス• メンバ関数でアクセスする場合

– ill-formed !!!

template<class T>struct Holder2 {

T v_;constexpr T const& value() const { return v_; } /* const版 */constexpr T& value() { return v_; } /* 非const版 */

};

Page 100: Constexpr 中3女子テクニック

◆データメンバアクセス• メンバ関数でアクセスする場合

– ill-formed !!!

• 返値型のみが異なるメンバ関数の定義と⾒做され、コン パイルエラーになる

template<class T>struct Holder2 {

T v_;constexpr T const& value() const { return v_; } /* const版 */constexpr T& value() const { return v_; } /* 非const版 */

};

constexpr メンバ関数が 暗黙で const 修飾される

Page 101: Constexpr 中3女子テクニック

◆データメンバアクセス• 非 const 版を constexpr

指定しない方法

template<class T>struct Holder2 {

T v_;constexpr T const& value() const { return v_; } /* const 版 */

T& value() { return v_; } /* 非 const 版 */};

Page 102: Constexpr 中3女子テクニック

◆データメンバアクセス• 非 const 版を constexpr

指定しない方法

• 非

const な

prvalue

rvalue

参照からのメンバ関数呼 び出しは、非

const 版が優先される

template<class T>struct Holder2 {

T v_;constexpr T const& value() const { return v_; } /* const 版 */

T& value() { return v_; } /* 非 const 版 */};

constexpr int i = Holder2<int>{ 100 }.value(); // Oops! 非 const 版が呼ばれる

Page 103: Constexpr 中3女子テクニック

◆データメンバアクセス• static メンバ関数を使う方法

template<class T>struct Holder3 {

T v_;static constexpr T const& value(Holder3 const& t) { return t.v_; }

/* const 版 */static constexpr T& value(Holder3& t) { return t.v_; }

/* 非 const 版 */};

Page 104: Constexpr 中3女子テクニック

◆データメンバアクセス• static メンバ関数を使う方法

template<class T>struct Holder3 {

T v_;static constexpr T const& value(Holder3 const& t) { return t.v_; }

/* const 版 */static constexpr T& value(Holder3& t) { return t.v_; }

/* 非 const 版 */};

constexpr int i = Holder3<int>::value( Holder3<int>{ 100 } ); // OK!

かなり書きづらい

Page 105: Constexpr 中3女子テクニック

template<class T>constexpr T const& value(Holder3<T> const& t) {

return Holder3<T>::value(t); /* const版 */}template<class T>constexpr T& value(Holder3<T>& t) {

return Holder3<T>::value(t); /* 非 const 版 */}

◆データメンバアクセス• フリー関数を使う方法

Page 106: Constexpr 中3女子テクニック

template<class T>constexpr T const& value(Holder3<T> const& t) {

return Holder3<T>::value(t); /* const版 */}template<class T>constexpr T& value(Holder3<T>& t) {

return Holder3<T>::value(t); /* 非 const 版 */}

◆データメンバアクセス• フリー関数を使う方法

constexpr int i = value( Holder3<int>{ 100 } ); // スッキリ!

Page 107: Constexpr 中3女子テクニック

◆データメンバアクセス• C++14 では、constexpr

メンバ関数が暗黙

const 修飾

されなくなる!

constexpr int i = Holder3<int>{ 100 }.value();

template<class T>struct Holder4 {

T v_;constexpr T const& value() const { return v_; } /* const 版 */constexpr T& value() { return v_; } /* 非 const 版 */

};

こうあって然るべき

Page 108: Constexpr 中3女子テクニック

◆メソッドチェイン• メソッドチェインでデータを処理するクラスの例

– const 版は次の状態のオブジェクトを返す– 非

const 版は内部状態を変更する

struct Hasher {constexpr Hasher process( Data const& src ) const; /* const 版 */constexpr void process( Data const& src ); /* 非 const 版 */constexpr Hashed finish() const; /* 結果を返す */

};

Page 109: Constexpr 中3女子テクニック

◆メソッドチェイン• メソッドチェインでデータを処理するクラスの例

constexpr auto hashed =Hasher().process(src1).process(src2).finish();

Page 110: Constexpr 中3女子テクニック

◆メソッドチェイン• メソッドチェインでデータを処理するクラスの例

ill-formed !!!–

constexpr

の有無では解決できない

constexpr auto hashed =Hasher().process(src1).process(src2).finish(); 非 const な prvalue や rvalue 参照から

のメンバ関数呼び出しは、非 const 版 が優先される

Page 111: Constexpr 中3女子テクニック

◆メソッドチェイン• const 修飾された

prvalue

を返す方法

struct Hasher {constexpr Hasher const process( Data const& src ) const; /* const 版 */constexpr void process( Data const& src ); /* 非 const 版 */constexpr Hashed finish() const; /* 結果を返す */

};

const 修飾

Page 112: Constexpr 中3女子テクニック

◆メソッドチェイン• const 修飾された

prvalue

を返す方法

constexpr

メンバ関数でメソッドチェインを⾏う場合、返値は const 修飾されたオブジェクトにすべき

constexpr auto hashed =as_const(Hasher()).process(src1).process(src2).finish(); OK!

Page 113: Constexpr 中3女子テクニック

◆その他• ポインタの扱い• 浮動小数点数の扱い

Page 114: Constexpr 中3女子テクニック

◆ポインタの扱い• 定数式評価においては、ポインタ型は

RandomAccessIterator

の仕様を満たさないp1 < p2 // compile error!

p1 - p2 // compile error!

順序⽐較が出来ない

ポインタ同士の減算が 出来ない

Page 115: Constexpr 中3女子テクニック

◆ポインタの扱い• 案

1 :

distance(p1, p2) で距離計算する

– 毎回線形オーダー

Ο(n) の計算を要する– p1 <= p2 であることを保証しなければならない

Page 116: Constexpr 中3女子テクニック

◆ポインタの扱い• 案

2 :

基準アドレスと基準からの距離を持ったイテ

レータでラップする– ⽐較や減算は、予め計算された距離をもとに算出する

Page 117: Constexpr 中3女子テクニック

◆ポインタの扱い• 案

2 :

基準アドレスと基準からの距離を持ったイテ

レータでラップする– ⽐較や減算は、予め計算された距離をもとに算出する– それ

Sprout

でできるよ!

#include <sprout/range.hpp>

constexpr int a[2] = { 1, 2 };constexpr auto rng = range::make_ptr_range( a ); // RandomAccess

Page 118: Constexpr 中3女子テクニック

◆浮動小数点数の扱い• 定数式評価で浮動小数点例外を発生する処理はコンパイ

ルエラーになる

constexpr auto NaN = numeric_limits<double>::quiet_NaN();

NaN == NaN; // OK. (non-signaling)NaN < NaN; // compile error! (signaling)

NaN の大小⽐較など

Page 119: Constexpr 中3女子テクニック

◆浮動小数点数の扱い• 浮動小数点数を扱う定数式で

NaN

に対応させたかった

らまず最初に

NaN

チェック

• GCC のビルトイン数学関数は定数式として使えるが、 規格上浮動小数点例外が発生する呼出はコンパイルエ

ラーになる– 例えば

NaN

±∞

などの極値を返すような呼出

– Sprout.Math

の数学関数は常に

non-signaling

な実装なので、 常に定数式で使える

Page 120: Constexpr 中3女子テクニック

◆これからの

constexpr

の話•

C++14 で変わる

constexpr

C++14 constexpr

の使⽤例•

更にこれからの

constexpr

Page 121: Constexpr 中3女子テクニック

◆C++14 で変わる

constexpr• ローカル変数の使⽤• 副作⽤の許可• 制御構文の使⽤• void がリテラル型に• メンバ関数の暗黙の

const の撤廃

• 抽象マシンモデルの採⽤• 標準ライブラリ

Page 122: Constexpr 中3女子テクニック

◆ローカル変数の使⽤• ローカル変数の使⽤

constexpr double heron(double a, double b, double c) {double s = (a+b+c)/2;return sqrt(s*(s-a)*(s-b)*(s-c) );

}

Page 123: Constexpr 中3女子テクニック

◆副作⽤の許可• 副作⽤の許可

• ただし、オブジェクトの寿命が定数式評価中に始まるも のでなければならない

– 定数式評価の外に副作⽤を及ぼすことは出来ない– 定数式評価全体で副作⽤がないことが保証される

template<class Iterator, class Distance>constexpr void advance( Iterator& it, Distance n ) {

it += n;}

Page 124: Constexpr 中3女子テクニック

◆制御構文の使⽤• 制御構文の使⽤

• if, switch, while, do-while, for, range-based for

template<class Range, class T>constexpr T accumulate( Range const& rng, T init ) {

for ( auto const& e : rng ) {init += e;

}return init;

}

Page 125: Constexpr 中3女子テクニック

◆void がリテラル型に• void がリテラル型に

• 返値が

void

の関数も

constexpr

指定できる

template<class Iterator>constexpr void sort( Iterator first, Iterator last );

Page 126: Constexpr 中3女子テクニック

◆メンバ関数の暗黙の

const の撤廃• メンバ関数の暗黙の

const の撤廃

• ただし、現時点のドラフトでは標準ライブラリのインタ フェースまで更新されていない

template<class T, size_t N>struct array {

constexpr T const& front() const;constexpr T& front();

};

Page 127: Constexpr 中3女子テクニック

◆抽象マシンモデルの採⽤• C++11では、constexpr 関数の評価は、関数呼び出し

の置換(function invocation substitution)という規則で 定義されていた

– 関数の評価を、呼び出し先の関数の式の評価と置換することで、 関数呼び出しをエミュレートする

– 式変形の最適化に近い

• C++14では、定数式の評価はC++抽象マシンのサブ セットとして再定義される

Page 128: Constexpr 中3女子テクニック

◆標準ライブラリ• 新たに

constexpr

指定されるもの

– forward, move, move_if_noexcept– tuple, pair

のほとんどの機能

– initializer_list

Page 129: Constexpr 中3女子テクニック

◆C++14 constexpr

の使⽤例• 可変⻑前方向リスト

#include <sprout/forward_clist.hpp>

constexpr int f() {using namespace sprout;

auto li = forward_clist<int>();{

decltype(li)::item it{ 10 };li.push_front(it);// { 10 }{

array<decltype(li)::item, 5> its{{ 100, 200, 300, 400, 500 }};li.insert_after(li.begin(), its.begin(), its.end());// { 10, 100, 200, 300, 400, 500 }/* ... */li.unlink(its.begin(), its.end());

}li.unlink(it);

}}

Page 130: Constexpr 中3女子テクニック

◆C++14 constexpr

の使⽤例• 可変⻑前方向リスト

#include <sprout/forward_clist.hpp>

constexpr int f() {using namespace sprout;

auto li = forward_clist<int>();{

decltype(li)::item it{ 10 };li.push_front(it);// { 10 }{

array<decltype(li)::item, 5> its{{ 100, 200, 300, 400, 500 }};li.insert_after(li.begin(), its.begin(), its.end());// { 10, 100, 200, 300, 400, 500 }/* ... */li.unlink(its.begin(), its.end());

}li.unlink(it);

}}

ノードはスタック上に無ければならな い(動的オブジェクトが使えない)ので、

ローカル変数として宣⾔

RAII が使えないので手動でリンク解除 が必要

Page 131: Constexpr 中3女子テクニック

◆更にこれからの

constexpr•

C++1y で応⽤される

constexpr

C++14 constexpr

の問題点•

標準ライブラリの更なる

constexpr

期待しうる

constexpr

の進化

Page 132: Constexpr 中3女子テクニック

◆C++1y で応⽤される

constexpr• N3627

: switch 文での利⽤

– constexpr

operator==()

で⽐較できるリテラル型を

switch 文で使えるようにする提案

• N3580

: Concept Lite– 型の制約を

constexpr

関数で表現する軽量コンセプトの提案

Page 133: Constexpr 中3女子テクニック

◆C++14 constexpr

の問題点• 例外安全性の問題

– ローカル変数と副作⽤が使えるようになったが、 ユーザ定義デストラクタが使えない

• つまり

RAII が使えない– try-catch ブロックが書けない

• つまり例外をハンドリングできない– 例外安全でない

constexpr

関数を簡単に書くことが

出来る– そのような関数を、インタフェースを変えずに例外

安全に書き直すのも困難

Page 134: Constexpr 中3女子テクニック

◆標準ライブラリの更なる

constexpr

• メンバ関数の暗黙の

const 修飾が撤廃されたた め、constexpr

メンバ関数のオーバーロードは、

ほぼ無条件で

constexpr

指定を付け加えられる と考えられる

• イテレータ関連の機能

Page 135: Constexpr 中3女子テクニック

◆期待しうる

constexpr

の進化• ラムダ式

– 相変わらずマングルの問題で⾒送られているが、議 論は続けられている

• new/delete– N3664(new のメモリ確保を実装が省略可能にする)

が採択されたので、コンパイル時に処理系が Dynamic storage duration 以外の記憶期間を使え

るよう変更されれば、コンパイル時

new

も許可され るかもしれない

Page 136: Constexpr 中3女子テクニック

◆期待しうる

constexpr

の進化• ユーザ定義リテラル

– テンプレートパラメータパックを受け取るユーザ定 義文字列リテラル

• コンパイル時

IO– 欲しい

Page 137: Constexpr 中3女子テクニック

◆まとめ•

C++11

のもっとも重要な新機能の一つである

constexpr

は、様々なテクニックを駆使して何 でも出来ることが示された

C++14

では、constexpr

が書きやすくなり、 モデルも刷新され、よりユーザフレンドリに

C++1y 以降では、constexpr

の更なる進化が 望める

constexpr

の今後に大いに期待しながらエン ジョイしよう!!

Page 138: Constexpr 中3女子テクニック

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