SlideShare a Scribd company logo
1 of 58
Download to read offline
中3女子が狂える
      本当に
    気持ちのいい
            constexpr
Boost.勉強会 #8
bolero_MURAKAMI
2012/2/11
◆⾃⼰紹介
• 名前 : 村上 原野    (むらかみ げんや)
      @bolero_MURAKAMI, id:boleros

• 棲息地: ⼤都会岡⼭

• 仕事 : 猪⾵来美術館 陶芸指導員
 ・普段はやきものの修⾏をしたり、
  縄⽂⼟器をつくったりしています
 ・趣味は constexpr です
◆⾃⼰紹介
• 開催中:
 – 村上原野 縄⽂⼟器展
   『ハロー、縄⽂!』
    〜2012/3/4
◆⾃⼰紹介
• 公開しているライブラリ:
 Sprout C++ Library (constexpr ライブラリ)
 github.com/bolero-MURAKAMI/Sprout


• 前回発表資料:
 【中3⼥⼦でもわかる constexpr】
 www.slideshare.net/GenyaMurakami
◆アジェンダ
•   はじめに
•   constexpr おさらい
•   constexpr と TMP の連携
•   (続)constexpr レイトレーシング
•   まとめ
◆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{ }; // クラスインスタンスを定数式に
◆constexpr とは?
• constexpr 関数の制限
 template<class T>                    関数テンプレートも
 constexpr T square(T const& n) {    constexpr 指定できる
   static_assert( true, “” );
   // static_assert( n != 0, “” );
   typedef T t1;
   using t2 = T;
   using std::ptrdiff_t;
   using namespace std;
   return n * n;
 }

   – static_assert, typedef, using, 及び⾼々1つの return ⽂のみ
     を書くことができる
   – 引数は定数式にならない
◆C++ プログラミングのレイヤー
   C++03         [処理されるもの]     [プログラマのすること]

 プリプロセス時の世界                       プリプロセッサ
    (魔界)           ソースコード
                                 メタプログラミング



                                 テンプレート
                     型
  コンパイル時の世界                     メタプログラミング
(ライブラリアンが多数棲息)
                      定数式




   実⾏時の世界          実⾏時オブジェクト
    (⼈間界)
                                 通常の
                                プログラミング
◆C++ プログラミングのレイヤー
   C++11         [処理されるもの]     [プログラマのすること]

 プリプロセス時の世界                       プリプロセッサ
    (魔界)           ソースコード
                                 メタプログラミング



                                 テンプレート
                     型
  コンパイル時の世界                     メタプログラミング
(ライブラリアンが多数棲息)
                      定数式
                                             constexpr


   実⾏時の世界          実⾏時オブジェクト
    (⼈間界)
                                 通常の
                                プログラミング
◆C++ プログラミングのレイヤー
   C++11         [処理されるもの]     [プログラマのすること]

 プリプロセス時の世界
                                        連携したい
                                  プリプロセッサ
    (魔界)           ソースコード
                                 メタプログラミング



                                 テンプレート
                     型
  コンパイル時の世界                     メタプログラミング
(ライブラリアンが多数棲息)
                      定数式
                                             constexpr


   実⾏時の世界          実⾏時オブジェクト
    (⼈間界)
                                 通常の
                                プログラミング
◆Sprout C++ Library
•   constexpr   ⽂字列
•   constexpr   タプル
•   constexpr   バリアント
•   constexpr   アルゴリズム
•   constexpr   範囲アルゴリズム
•   constexpr   コンテナ操作
•   constexpr   乱数
•   constexpr   ハッシュ関数
•   constexpr   UUID
•   constexpr   構⽂解析
•   constexpr   レイトレーシング
◆Sprout C++ Library
• constexpr ⽂字列
 #include <sprout/string.hpp>
 #include <sprout/algorithm.hpp>

 /* コンパイル時文字列 */
 static constexpr auto hello = sprout::to_string("Hello,world!");
 static_assert( hello == "Hello,world!", "" );

 /* 文字列連結 */
 static_assert( hello + "!!!" == "Hello,world!!!!", "" );

 /* 文字列切り出し */
 static_assert( hello.substr(0, 5) == "Hello", "" );

 /* 文字列反転 */
 static_assert( sprout::reverse(hello) == "!dlrow,olleH", "" );
◆Sprout C++ Library
• constexpr ⽂字列
 #include <sprout/string.hpp>
 #include <sprout/algorithm.hpp>

 /* コンパイル時文字列 */
 static constexpr auto hello = sprout::to_string("Hello,world!");
 static_assert( hello == "Hello,world!", "" );

 /* 文字列連結 */
 static_assert( hello + "!!!" == "Hello,world!!!!", "" );

 /* 文字列切り出し */
 static_assert( hello.substr(0, 5) == "Hello", "" );

 /* 文字列反転 */
 static_assert( sprout::reverse(hello) == "!dlrow,olleH", "" );


                 このように、constexpr で様々なクラスを
                とてもわかりやすく簡単に扱うことができる。
◆constexpr と TMP の連携
• クラステンプレートにコンパイル時定数
  を渡すには
• index_tuple idiom
• 型⽂字列と constexpr ⽂字列の相互変換
◆クラステンプレートにコンパイル時定数を渡すには
• 整数型を渡す
template<int W, int H> RectArea {
   static constexpr int value = W * H;
};
static constexpr int w = 50;
static constexpr int h = 100;
static_assert( RectArea<w, h>::value == 5000, “” )
◆クラステンプレートにコンパイル時定数を渡すには
• 整数型を渡す                                 整数型はテンプレート引数に
template<int W, int H> RectArea {           そのまま渡せる
   static constexpr int value = W * H;
};
static constexpr int w = 50;
static constexpr int h = 100;
static_assert( RectArea<w, h>::value == 5000, “” )
◆クラステンプレートにコンパイル時定数を渡すには
• 整数型以外のオブジェクトを渡すには?
struct Rect { int w; int h; };

template< ??? >
struct Area {
   static constexpr int value = ???;
};
◆クラステンプレートにコンパイル時定数を渡すには
• 整数型以外のオブジェクトを渡すには?
struct Rect { int w; int h; };         このクラスのインスタンスを
                                        テンプレートに渡したい
template< ??? >
struct Area {                           テンプレート引数を
   static constexpr int value = ???;     どう書けばいい?
};
◆クラステンプレートにコンパイル時定数を渡すには
• クラスを直接テンプレート引数にしてみる
template<Rect V>
struct Area {
   static constexpr int value = V.w * V.h;
};

static constexpr Rect rect = {10, 20};
static_assert( Area<rect>::value == 200, “” );
◆クラステンプレートにコンパイル時定数を渡すには
• クラスを直接テンプレート引数にしてみる
template<Rect V>                           コンパイルエラー!!
struct Area {
   static constexpr int value = V.w * V.h;
};

static constexpr Rect rect = {10, 20};
static_assert( Area<rect>::value == 200, “” );



• クラス型をテンプレート引数にすることはできない
• 論外
◆クラステンプレートにコンパイル時定数を渡すには
• ポインタをテンプレート引数にしてみる
template<Rect const* P>
struct Area {
   static constexpr int value = P->w * P->h;
};

static constexpr Rect rect = {10, 20};
static_assert( Area<&rect>::value == 200, “” );
◆クラステンプレートにコンパイル時定数を渡すには
• ポインタをテンプレート引数にしてみる
template<Rect const* P>
struct Area {
   static constexpr int value = P->w * P->h;
};
                                                  OK!
static constexpr Rect rect = {10, 20};
static_assert( Area<&rect>::value == 200, “” );



• ポインタ型をテンプレート引数にすることは可能
◆クラステンプレートにコンパイル時定数を渡すには
• ポインタをテンプレート引数にしてみる
template<Rect const* P>
struct Area {
   static constexpr int value = P->w * P->h;
};

int main() {
   static constexpr Rect rect = {10, 20};
   static_assert( Area<&rect>::value == 200, “” );
}
◆クラステンプレートにコンパイル時定数を渡すには
• ポインタをテンプレート引数にしてみる
template<Rect const* P>
struct Area {
   static constexpr int value = P->w * P->h;
};

int main() {                                       コンパイルエラー!!
   static constexpr Rect rect = {10, 20};
   static_assert( Area<&rect>::value == 200, “” );
}

• テンプレート引数に渡せる値
  – 整数型 / リンケージを持つオブジェクト
• ローカル変数、⼀時オブジェクト、⽂字列リテラル等を
  テンプレート引数に渡すことはできない
◆クラステンプレートにコンパイル時定数を渡すには
• プロキシクラスをテンプレート引数にしてみる
template<class Proxy>
struct Area {
   static constexpr int value = Proxy()().w * Proxy()().h;
};

int main() {
   static constexpr Rect rect = {10, 20};
      struct proxy {
         constexpr Rect const& operator()() const { return rect; }
      };
   static_assert( Area<proxy>::value == 200, “” );
}
◆クラステンプレートにコンパイル時定数を渡すには
• プロキシクラスをテンプレート引数にしてみる
 template<class Proxy>
 struct Area {                                     プロキシを介して値を取得
    static constexpr int value = Proxy()().w * Proxy()().h;
 };

 int main() {                                proxy クラスの operator() は
    static constexpr Rect rect = {10, 20};    ローカル変数の Rect を返す
       struct proxy {
          constexpr Rect const& operator()() const { return rect; }
       };
    static_assert( Area<proxy>::value == 200, “” );
 }                                                                OK!

• 短所
  – プロキシクラスをいちいち定義しなければならない
◆クラステンプレートにコンパイル時定数を渡すには
• ポインタをテンプレート引数にする⽅法
template<Object const* P>
struct TemplateClass;

 – リンケージを持つオブジェクト(グローバル変数)しか渡すこと
   ができない


• プロキシクラスをテンプレート引数にする⽅法
template<class Proxy>
struct TemplateClass;

 – その都度プロキシクラスを作成する必要がある
 – (プロキシの定義をマクロにすれば多少書きやすいかも)
◆index_tuple idiom
• index_tuple と index_range ヘルパ
 template<ptrdiff_t... Indexes>
 struct index_tuple;

 template<ptrdiff_t First, ptrdiff_t Last>
 struct index_range;

 static_assert( std::is_same<
    index_range<0, 5>::type,
    index_tuple<0, 1, 2, 3, 4>
    >::value, “” );
◆index_tuple idiom
• index_tuple と index_range ヘルパ
 template<ptrdiff_t... Indexes>                  パラメータパックを
 struct index_tuple;                         pack expansion expression
                                                (Indexes...) で使う
 template<ptrdiff_t First, ptrdiff_t Last>
 struct index_range;
                                                (First .. Last] の
                                             index_tuple を⽣成する
 static_assert( std::is_same<
                                                 ヘルパメタ関数
    index_range<0, 5>::type,
    index_tuple<0, 1, 2, 3, 4>
    >::value, “” );
◆index_tuple idiom
• TMP で index_tuple を使う
 #include <sprout/index_tuple.hpp>
 #include <boost/mpl/vector.hpp>

 template<class Seq, class IndexTuple>
 struct to_tuple_impl;
 template<class Seq, ptrdiff_t... Indexes>
 struct to_tuple_impl<Seq, index_tuple<Indexes...> > {
    typedef tuple< mpl::at_c<Seq, Indexes>... > type;
 };
 /* MPLシーケンスから tuple への変換 */
 template<class Seq>
 struct to_tuple : to_tuple_impl<
    Seq,
    typename index_range<0, mpl::size<Seq>::value>::type
 > { };

 typedef mpl::vector<int, double> vec;
 static_assert( is_same<to_tuple<vec>::type, tuple<int, double> >::value, “” );
◆index_tuple idiom
• TMP で index_tuple を使う
 #include <sprout/index_tuple.hpp>
 #include <boost/mpl/vector.hpp>
                                             index_tuple<Indexes...> で
 template<class Seq, class IndexTuple>        テンプレート引数を特殊化する
 struct to_tuple_impl;
 template<class Seq, ptrdiff_t... Indexes>
 struct to_tuple_impl<Seq, index_tuple<Indexes...> > {
    typedef tuple< mpl::at_c<Seq, Indexes>... > type;
 };
 /* MPLシーケンスから tuple への変換 */                  pack expansion expression で
 template<class Seq>                          Indexes を使ったリストに展開する
 struct to_tuple : to_tuple_impl<
    Seq,
    typename index_range<0, mpl::size<Seq>::value>::type
 > { };
                                                      index_range で index_tuple を
                                                           ⽣成して実装に丸投げ
 typedef mpl::vector<int, double> vec;
 static_assert( is_same<to_tuple<vec>::type, tuple<int, double> >::value, “” );
◆index_tuple idiom
• constexpr 関数で index_tuple を使う

 #include <sprout/index_tuple.hpp>
 #include <sprout/array.hpp>

 template<class T, size_t N, ptrdiff_t...Indexes>
 constexpr array<T, N> to_array_impl(T const (& arr)[N], index_tuple<Indexes...>) {
    return array<T, N>{{ arr[Indexes]... }};
 }
 /* 生配列から sprout::array への変換 */
 template<class T, size_t N>
 constexpr array<T, N> to_array(T const (& arr)[N]) {
    return to_array_impl(arr, typename index_range<0, N>::type());
 }

 static constexpr int arr[2] = { 1, 2 };
 static constexpr array<int, 2> s = to_array(arr);
◆index_tuple idiom
• constexpr 関数で index_tuple を使う

 #include <sprout/index_tuple.hpp>                   index_tuple<Indexes...>
 #include <sprout/array.hpp>                           を引数にして推論させる

 template<class T, size_t N, ptrdiff_t...Indexes>
 constexpr array<T, N> to_array_impl(T const (& arr)[N], index_tuple<Indexes...>) {
    return array<T, N>{{ arr[Indexes]... }};
 }
                                              pack expansion expression で
 /* 生配列から sprout::array への変換 */
                                              Indexes を使ったリストに展開する
 template<class T, size_t N>
 constexpr array<T, N> to_array(T const (& arr)[N]) {
    return to_array_impl(arr, typename index_range<0, N>::type());
 }
                                                     index_range で index_tuple を
 static constexpr int arr[2] = { 1, 2 };                  ⽣成して実装に丸投げ
 static constexpr array<int, 2> s = to_array(arr);
◆index_tuple idiom
• index_tuple イディオムは、インデックスアクセス可能
  なデータ構造⼀般に適⽤できる
 –   配列
 –   タプル
 –   ランダムアクセスイテレータ
 –   型リスト

• constexpr に限らず、通常の関数や TMP にも同じよう
  に応⽤できる

• ただしインデックスアクセス不可なデータ構造には適⽤
  できない
 – ⾮ランダムアクセスなイテレータなど
◆型⽂字列と constexpr ⽂字列の相互変換
• 型⽂字列
 typedef mpl::string< ‘Hell’, ‘o,wo’, ‘rld!’ > hello_t;
   – ⽂字列は可変⻑テンプレート引数で表現される
   – ⽂字列リテラルは使えない
        • (マクロの⿊魔術を使えば制限付きで可能ではある)


• constexpr ⽂字列
 static constexpr auto hello = sprout::to_string( “Hello,world!” );

   – コンパイル時定数である
   – ⽂字列リテラルが使⽤可能


• これらを相互に変換できるようにしたい
◆型⽂字列と constexpr ⽂字列の相互変換
• mpl::string → sprout::string



 #include <type_traits>
 #include <sprout/index_tuple.hpp>
 #include <sprout/type.hpp>
 #include <sprout/string.hpp>
 #include <sprout/type/boost/mpl/string.hpp>

 using namespace std;
 using namespace sprout;
 namespace mpl = boost::mpl;
 namespace types = sprout::types;
◆型⽂字列と constexpr ⽂字列の相互変換
• mpl::string → sprout::string
 /* T::value がナル文字であるか返すメタ関数クラス */
 struct is_nul {
    template<class T, class = void>
    struct apply : false_type { };
    template<class T>
    struct apply<T, typename enable_if<T::value == 0>::type>
       : true_type
    { };
 };
 /* ナル文字までの文字列長 */
 template<class Seq>
 struct str_length : types::distance<
    typename types::begin<Seq>::type,
    typename types::seq::find_if<Seq, is_nul>::type
 > { };
◆型⽂字列と constexpr ⽂字列の相互変換
• mpl::string → sprout::string
 template<class Seq, ptrdiff_t... Indexes>
 constexpr sprout::basic_string<
    typename Seq::value_type,
    str_length<Seq>::value
 > to_sprout_string_impl( index_tuple<Indexes...> ) {
    return sprout::make_string_as<typename Seq::value_type>(
       types::tuple_element<Indexes, Seq>::type::value...
       );
 }
 /* sprout::string に変換 */
 template<class Seq>
 constexpr sprout::basic_string<
    typename Seq::value_type,
    str_length<Seq>::value
 > to_sprout_string() {
    return to_sprout_string_impl<Seq>(
       typename index_range<0, str_length<Seq>::value>::type()
       );
 }
◆型⽂字列と constexpr ⽂字列の相互変換
• mpl::string → sprout::string
 template<class Seq, ptrdiff_t... Indexes>
 constexpr sprout::basic_string<
                                                 index_tuple<Indexes...> を
    typename Seq::value_type,
                                                       実装関数で受け取る
    str_length<Seq>::value
 > to_sprout_string_impl( index_tuple<Indexes...> ) {
    return sprout::make_string_as<typename Seq::value_type>(
       types::tuple_element<Indexes, Seq>::type::value...
       );                                           Indexes を使ってシーケンス要素の
 }                                                         ⽂字のリストに展開
 /* sprout::string に変換 */
 template<class Seq>
 constexpr sprout::basic_string<           basic_string<Elem, Length>
    typename Seq::value_type,
    str_length<Seq>::value                         index_range で index_tuple を
 > to_sprout_string() {                                  ⽣成して実装に丸投げ
    return to_sprout_string_impl<Seq>(
       typename index_range<0, str_length<Seq>::value>::type()
       );
 }
◆型⽂字列と constexpr ⽂字列の相互変換
• mpl::string → sprout::string

 typedef mpl::string< ‘foo’, ‘bar’ > type;
 static constexpr auto s = to_sprout_string<type>();
 static_assert( s == “foobar”, “” );

                                              mpl::string (型)から
                                     sprout::string (コンパイル時定数)へ変換

• ⼀般に【型→値】の変換は⾃明に書ける(場合が多い)
◆型⽂字列と constexpr ⽂字列の相互変換
• sprout::string → mpl::string



 #include <type_traits>
 #include <sprout/index_tuple.hpp>
 #include <sprout/fixed_container.hpp>
 #include <sprout/string.hpp>
 #include <boost/mpl/string.hpp>
 #include <boost/preprocessor/cat.hpp>

 using namespace std;
 using namespace sprout;
 namespace mpl = boost::mpl;
◆型⽂字列と constexpr ⽂字列の相互変換
• sprout::string → mpl::string
 template<class Proxy>
 struct to_mpl_string {
    template<class IndexTuple>
    struct impl;
    template<ptrdiff_t... Indexes>
    struct impl<index_tuple<Indexes...> > {
       typedef mpl::string<
          sprout::begin(Proxy()())[Indexes]...
       > type;
    };
    /* mpl::string に変換 */
    typedef class impl<
       typename index_range<0, sprout::size(Proxy()())>::type
    >::type type;
 };
◆型⽂字列と constexpr ⽂字列の相互変換
• sprout::string → mpl::string
 template<class Proxy>                 index_tuple<Indexes...> を
 struct to_mpl_string {                   実装メタ関数で受け取る
    template<class IndexTuple>
    struct impl;
    template<ptrdiff_t... Indexes>
    struct impl<index_tuple<Indexes...> > {
       typedef mpl::string<                       mpl::string<Elem...>
          sprout::begin(Proxy()())[Indexes]...
       > type;
    };                                   Indexes を使ってシーケンス要素の
    /* mpl::string に変換 */                       ⽂字のリストに展開
    typedef class impl<
       typename index_range<0, sprout::size(Proxy()())>::type
    >::type type;
 };
                                  index_range で index_tuple を
                                       ⽣成して実装に丸投げ
◆型⽂字列と constexpr ⽂字列の相互変換
• sprout::string → mpl::string



 /* 変換結果を typedef するマクロ*/
 #define STRING_CLASS_TYPEDEF(SOURCE, TYPE) ¥
 struct BOOST_PP_CAT(PROXY_, __LINE__) { ¥
    constexpr typename remove_reference<decltype(SOURCE)>::type ¥
    operator() () const { return SOURCE; } ¥
 }; ¥
 typedef typename to_mpl_string< ¥
    BOOST_PP_CAT(PROXY_, __LINE__) ¥
    >::type TYPE
◆型⽂字列と constexpr ⽂字列の相互変換
• sprout::string → mpl::string


                                     PROXY_127 のような名前の
                                     プロキシクラスが定義される
 /* 変換結果を typedef するマクロ*/
 #define STRING_CLASS_TYPEDEF(SOURCE, TYPE) ¥
 struct BOOST_PP_CAT(PROXY_, __LINE__) { ¥
    constexpr typename remove_reference<decltype(SOURCE)>::type ¥
    operator() () const { return SOURCE; } ¥
 }; ¥                                          operator() は変換元ソースを
 typedef typename to_mpl_string< ¥             そのまま返す constexpr 関数
    BOOST_PP_CAT(PROXY_, __LINE__) ¥
    >::type TYPE
                        定義したプロキシクラスを渡す
◆型⽂字列と constexpr ⽂字列の相互変換
• sprout::string → mpl::string
 #include <boost/mpl/equal.hpp>           sprout::string (コンパイル時定数)から
                                                 mpl::string (型)へ変換
 static constexpr auto s = sprout::to_string( “foobar” );
 STRING_CLASS_TYPEDEF(s, type);
 static_assert( mpl::equal< type, mpl::string<'foo', 'bar'> >::value, “” );



• 【値→型】の変換は⼯夫次第で可能
• ⽋点
   – ⾃明な書き⽅ができない(場合が多い)
   – プロキシクラスの定義が必要な場合、インラインに書けないし、
     constexpr 関数の中で使えない
◆constexpr と TMP の連携
• 整数型以外のコンパイル時定数でも、テンプ
  レートに受け渡す⽅法はある

• index_tuple イディオムや、プロキシクラス等
  を活⽤することで、constexpr と TMP の間で
  相互にやりとりをすることができる
◆(続)constexpr レイトレーシング
• Sprout.Darkroom
  – metatrace という TMP ライブラリを元にした constexpr レイ
    トレーサーライブラリ
◆(続)constexpr レイトレーシング
• 2つの球(Boost.勉強会#7 東京時点)
◆(続)constexpr レイトレーシング
• 鏡の部屋の2つの球
◆(続)constexpr レイトレーシング
• 鏡の部屋の2つの球(市松模様の床)
◆(続)constexpr レイトレーシング
• 地球のような何か
◆(続)constexpr レイトレーシング
• エレメント(カラーやスペキュラ)を表現するには
template<typename Element, typename Scale>
class plaid_element {
private:
   Element elem1_;
   Element elem2_;
   Scale scale_;
   template<typename Unit>
   constexpr Element calc_1(Unit const& u, Unit const& v) const {
     return (u >= 0 && v >= 0) || (u < 0 && v < 0)
         ? elem1_ : elem2_;
   }
public:
   template<typename Unit>
   constexpr Element operator() (Unit const& u, Unit const& v) const {
     return calc_1(
         (u < 0 ? scale_ + fmod(u, scale_) : fmod(u, scale_)) - scale_ / 2,
         (v < 0 ? scale_ + fmod(v, scale_) : fmod(v, scale_)) - scale_ / 2
         );
   }
};
◆(続)constexpr レイトレーシング
• エレメント(カラーやスペキュラ)を表現するには
template<typename Element, typename Scale>
class plaid_element {
private:                            市松模様を表現するエレメント
   Element elem1_;
   Element elem2_;                                 座標を⼆つに分けて
   Scale scale_;                        どちらかのエレメント(⽩/⿊など)を返す
   template<typename Unit>
   constexpr Element calc_1(Unit const& u, Unit const& v) const {
     return (u >= 0 && v >= 0) || (u < 0 && v < 0)
         ? elem1_ : elem2_;
                                                       エレメントのコンセプトは
   }
                                                   uv 座標を受け取って結果を返す
public:
                                                     operator()(u, v) を持つこと
   template<typename Unit>
   constexpr Element operator() (Unit const& u, Unit const& v) const {
     return calc_1(
         (u < 0 ? scale_ + fmod(u, scale_) : fmod(u, scale_)) - scale_ / 2,
         (v < 0 ? scale_ + fmod(v, scale_) : fmod(v, scale_)) - scale_ / 2
         );
   }
};
◆(続)constexpr レイトレーシング
• テクスチャマップを読み込むには
#include <sprout/darkroom.hpp>

/* ファイル "earth.tex.hpp" の内容を tex に読み込む */
#define DARKROOM_DEF_LOAD_TEXTURE_IDENTIFIER tex
#define DARKROOM_DEF_LOAD_TEXTURE_FILE "earth.tex.hpp"
#include DARKROOM_LOAD_TEXTURE


 – earth.png
◆(続)constexpr レイトレーシング
• テクスチャマップを読み込むには
#include <sprout/darkroom.hpp>

/* ファイル "earth.tex.hpp" の内容を tex に読み込む */
#define DARKROOM_DEF_LOAD_TEXTURE_IDENTIFIER tex
#define DARKROOM_DEF_LOAD_TEXTURE_FILE "earth.tex.hpp"
#include DARKROOM_LOAD_TEXTURE


 – 擬似コード
/* 実装は include ディレクティブで CVS を取りこむトリックと同じような感じ */
constexpr auto tex {
# include "earth.tex.hpp"
};
                            “earth.tex.hpp” の中⾝は
                        コンマ区切りのピクセルデータのようなもの
◆まとめ
• constexpr を活⽤することで、『型』
  『オブジェクト』『外部データ』等さま
  ざまなソースを、コンパイル時に相互に
  扱うことができる

• constexpr でもっともっと遊ぼう!!
ご清聴
 ありがとう
ございました

More Related Content

What's hot

闇魔術を触ってみた
闇魔術を触ってみた闇魔術を触ってみた
闇魔術を触ってみたSatoshi Sato
 
コルーチンでC++でも楽々ゲーム作成!
コルーチンでC++でも楽々ゲーム作成!コルーチンでC++でも楽々ゲーム作成!
コルーチンでC++でも楽々ゲーム作成!amusementcreators
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門Norishige Fukushima
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門natrium11321
 
不遇の標準ライブラリ - valarray
不遇の標準ライブラリ - valarray不遇の標準ライブラリ - valarray
不遇の標準ライブラリ - valarrayRyosuke839
 
競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性Hibiki Yamashiro
 
すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!Genya Murakami
 
C# 8.0 非同期ストリーム
C# 8.0 非同期ストリームC# 8.0 非同期ストリーム
C# 8.0 非同期ストリーム信之 岩永
 
規格書で読むC++11のスレッド
規格書で読むC++11のスレッド規格書で読むC++11のスレッド
規格書で読むC++11のスレッドKohsuke Yuasa
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するYoshifumi Kawai
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装MITSUNARI Shigeo
 
C++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるHideyuki Tanaka
 
クソザコ鳥頭が非順序連想コンテナに入門してみた
クソザコ鳥頭が非順序連想コンテナに入門してみたクソザコ鳥頭が非順序連想コンテナに入門してみた
クソザコ鳥頭が非順序連想コンテナに入門してみたMitsuru Kariya
 
Effective Modern C++ 勉強会 Item 22
Effective Modern C++ 勉強会 Item 22Effective Modern C++ 勉強会 Item 22
Effective Modern C++ 勉強会 Item 22Keisuke Fukuda
 
C++の話(本当にあった怖い話)
C++の話(本当にあった怖い話)C++の話(本当にあった怖い話)
C++の話(本当にあった怖い話)Yuki Tamura
 
.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理KageShiron
 

What's hot (20)

闇魔術を触ってみた
闇魔術を触ってみた闇魔術を触ってみた
闇魔術を触ってみた
 
コルーチンでC++でも楽々ゲーム作成!
コルーチンでC++でも楽々ゲーム作成!コルーチンでC++でも楽々ゲーム作成!
コルーチンでC++でも楽々ゲーム作成!
 
C++の黒魔術
C++の黒魔術C++の黒魔術
C++の黒魔術
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門
 
C++ マルチスレッド 入門
C++ マルチスレッド 入門C++ マルチスレッド 入門
C++ マルチスレッド 入門
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門
 
最速C# 7.x
最速C# 7.x最速C# 7.x
最速C# 7.x
 
不遇の標準ライブラリ - valarray
不遇の標準ライブラリ - valarray不遇の標準ライブラリ - valarray
不遇の標準ライブラリ - valarray
 
プログラムを高速化する話
プログラムを高速化する話プログラムを高速化する話
プログラムを高速化する話
 
競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性
 
すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!
 
C# 8.0 非同期ストリーム
C# 8.0 非同期ストリームC# 8.0 非同期ストリーム
C# 8.0 非同期ストリーム
 
規格書で読むC++11のスレッド
規格書で読むC++11のスレッド規格書で読むC++11のスレッド
規格書で読むC++11のスレッド
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装
 
C++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISる
 
クソザコ鳥頭が非順序連想コンテナに入門してみた
クソザコ鳥頭が非順序連想コンテナに入門してみたクソザコ鳥頭が非順序連想コンテナに入門してみた
クソザコ鳥頭が非順序連想コンテナに入門してみた
 
Effective Modern C++ 勉強会 Item 22
Effective Modern C++ 勉強会 Item 22Effective Modern C++ 勉強会 Item 22
Effective Modern C++ 勉強会 Item 22
 
C++の話(本当にあった怖い話)
C++の話(本当にあった怖い話)C++の話(本当にあった怖い話)
C++の話(本当にあった怖い話)
 
.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理
 

Similar to 中3女子が狂える本当に気持ちのいい constexpr

C++0x 言語の未来を語る
C++0x 言語の未来を語るC++0x 言語の未来を語る
C++0x 言語の未来を語るAkira Takahashi
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門伸男 伊藤
 
リテラル文字列型までの道
リテラル文字列型までの道リテラル文字列型までの道
リテラル文字列型までの道Satoshi Sato
 
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~Akira Inoue
 
わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61TATSUYA HAYAMIZU
 
JAWSDAYS 2014 ACEに聞け! EMR編
JAWSDAYS 2014 ACEに聞け! EMR編JAWSDAYS 2014 ACEに聞け! EMR編
JAWSDAYS 2014 ACEに聞け! EMR編陽平 山口
 
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~Akira Inoue
 
Boost.Flyweight
Boost.FlyweightBoost.Flyweight
Boost.Flyweightgintenlabo
 
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜Hiromi Ishii
 
Scalaプログラミング・マニアックス
Scalaプログラミング・マニアックスScalaプログラミング・マニアックス
Scalaプログラミング・マニアックスTomoharu ASAMI
 
.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#信之 岩永
 
JavaScriptクイックスタート
JavaScriptクイックスタートJavaScriptクイックスタート
JavaScriptクイックスタートShumpei Shiraishi
 
C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1信之 岩永
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputingNoboru Irieda
 
C# 8.0 Preview in Visual Studio 2019 (16.0)
C# 8.0 Preview in Visual Studio 2019 (16.0)C# 8.0 Preview in Visual Studio 2019 (16.0)
C# 8.0 Preview in Visual Studio 2019 (16.0)信之 岩永
 

Similar to 中3女子が狂える本当に気持ちのいい constexpr (20)

C++0x 言語の未来を語る
C++0x 言語の未来を語るC++0x 言語の未来を語る
C++0x 言語の未来を語る
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
 
リテラル文字列型までの道
リテラル文字列型までの道リテラル文字列型までの道
リテラル文字列型までの道
 
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
 
Boost Tour 1.50.0 All
Boost Tour 1.50.0 AllBoost Tour 1.50.0 All
Boost Tour 1.50.0 All
 
わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61
 
JAWSDAYS 2014 ACEに聞け! EMR編
JAWSDAYS 2014 ACEに聞け! EMR編JAWSDAYS 2014 ACEに聞け! EMR編
JAWSDAYS 2014 ACEに聞け! EMR編
 
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
 
Introduction of Python
Introduction of PythonIntroduction of Python
Introduction of Python
 
What is template
What is templateWhat is template
What is template
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
Boost.Flyweight
Boost.FlyweightBoost.Flyweight
Boost.Flyweight
 
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
 
Scalaプログラミング・マニアックス
Scalaプログラミング・マニアックスScalaプログラミング・マニアックス
Scalaプログラミング・マニアックス
 
.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#
 
JavaScriptクイックスタート
JavaScriptクイックスタートJavaScriptクイックスタート
JavaScriptクイックスタート
 
Cocoa勉強会201208
Cocoa勉強会201208Cocoa勉強会201208
Cocoa勉強会201208
 
C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputing
 
C# 8.0 Preview in Visual Studio 2019 (16.0)
C# 8.0 Preview in Visual Studio 2019 (16.0)C# 8.0 Preview in Visual Studio 2019 (16.0)
C# 8.0 Preview in Visual Studio 2019 (16.0)
 

Recently uploaded

論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video UnderstandingToru Tamaki
 
Utilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsUtilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsWSO2
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイスCRI Japan, Inc.
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルCRI Japan, Inc.
 
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Gamesatsushi061452
 
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...Toru Tamaki
 
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptxsn679259
 

Recently uploaded (10)

論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
 
Utilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsUtilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native Integrations
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
 
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
 
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
 
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
 

中3女子が狂える本当に気持ちのいい constexpr

  • 1. 中3女子が狂える 本当に 気持ちのいい constexpr Boost.勉強会 #8 bolero_MURAKAMI 2012/2/11
  • 2. ◆⾃⼰紹介 • 名前 : 村上 原野 (むらかみ げんや) @bolero_MURAKAMI, id:boleros • 棲息地: ⼤都会岡⼭ • 仕事 : 猪⾵来美術館 陶芸指導員 ・普段はやきものの修⾏をしたり、 縄⽂⼟器をつくったりしています ・趣味は constexpr です
  • 3. ◆⾃⼰紹介 • 開催中: – 村上原野 縄⽂⼟器展 『ハロー、縄⽂!』 〜2012/3/4
  • 4. ◆⾃⼰紹介 • 公開しているライブラリ: Sprout C++ Library (constexpr ライブラリ) github.com/bolero-MURAKAMI/Sprout • 前回発表資料: 【中3⼥⼦でもわかる constexpr】 www.slideshare.net/GenyaMurakami
  • 5. ◆アジェンダ • はじめに • constexpr おさらい • constexpr と TMP の連携 • (続)constexpr レイトレーシング • まとめ
  • 6. ◆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{ }; // クラスインスタンスを定数式に
  • 7. ◆constexpr とは? • constexpr 関数の制限 template<class T> 関数テンプレートも constexpr T square(T const& n) { constexpr 指定できる static_assert( true, “” ); // static_assert( n != 0, “” ); typedef T t1; using t2 = T; using std::ptrdiff_t; using namespace std; return n * n; } – static_assert, typedef, using, 及び⾼々1つの return ⽂のみ を書くことができる – 引数は定数式にならない
  • 8. ◆C++ プログラミングのレイヤー C++03 [処理されるもの] [プログラマのすること] プリプロセス時の世界 プリプロセッサ (魔界) ソースコード メタプログラミング テンプレート 型 コンパイル時の世界 メタプログラミング (ライブラリアンが多数棲息) 定数式 実⾏時の世界 実⾏時オブジェクト (⼈間界) 通常の プログラミング
  • 9. ◆C++ プログラミングのレイヤー C++11 [処理されるもの] [プログラマのすること] プリプロセス時の世界 プリプロセッサ (魔界) ソースコード メタプログラミング テンプレート 型 コンパイル時の世界 メタプログラミング (ライブラリアンが多数棲息) 定数式 constexpr 実⾏時の世界 実⾏時オブジェクト (⼈間界) 通常の プログラミング
  • 10. ◆C++ プログラミングのレイヤー C++11 [処理されるもの] [プログラマのすること] プリプロセス時の世界 連携したい プリプロセッサ (魔界) ソースコード メタプログラミング テンプレート 型 コンパイル時の世界 メタプログラミング (ライブラリアンが多数棲息) 定数式 constexpr 実⾏時の世界 実⾏時オブジェクト (⼈間界) 通常の プログラミング
  • 11. ◆Sprout C++ Library • constexpr ⽂字列 • constexpr タプル • constexpr バリアント • constexpr アルゴリズム • constexpr 範囲アルゴリズム • constexpr コンテナ操作 • constexpr 乱数 • constexpr ハッシュ関数 • constexpr UUID • constexpr 構⽂解析 • constexpr レイトレーシング
  • 12. ◆Sprout C++ Library • constexpr ⽂字列 #include <sprout/string.hpp> #include <sprout/algorithm.hpp> /* コンパイル時文字列 */ static constexpr auto hello = sprout::to_string("Hello,world!"); static_assert( hello == "Hello,world!", "" ); /* 文字列連結 */ static_assert( hello + "!!!" == "Hello,world!!!!", "" ); /* 文字列切り出し */ static_assert( hello.substr(0, 5) == "Hello", "" ); /* 文字列反転 */ static_assert( sprout::reverse(hello) == "!dlrow,olleH", "" );
  • 13. ◆Sprout C++ Library • constexpr ⽂字列 #include <sprout/string.hpp> #include <sprout/algorithm.hpp> /* コンパイル時文字列 */ static constexpr auto hello = sprout::to_string("Hello,world!"); static_assert( hello == "Hello,world!", "" ); /* 文字列連結 */ static_assert( hello + "!!!" == "Hello,world!!!!", "" ); /* 文字列切り出し */ static_assert( hello.substr(0, 5) == "Hello", "" ); /* 文字列反転 */ static_assert( sprout::reverse(hello) == "!dlrow,olleH", "" ); このように、constexpr で様々なクラスを とてもわかりやすく簡単に扱うことができる。
  • 14. ◆constexpr と TMP の連携 • クラステンプレートにコンパイル時定数 を渡すには • index_tuple idiom • 型⽂字列と constexpr ⽂字列の相互変換
  • 15. ◆クラステンプレートにコンパイル時定数を渡すには • 整数型を渡す template<int W, int H> RectArea { static constexpr int value = W * H; }; static constexpr int w = 50; static constexpr int h = 100; static_assert( RectArea<w, h>::value == 5000, “” )
  • 16. ◆クラステンプレートにコンパイル時定数を渡すには • 整数型を渡す 整数型はテンプレート引数に template<int W, int H> RectArea { そのまま渡せる static constexpr int value = W * H; }; static constexpr int w = 50; static constexpr int h = 100; static_assert( RectArea<w, h>::value == 5000, “” )
  • 18. ◆クラステンプレートにコンパイル時定数を渡すには • 整数型以外のオブジェクトを渡すには? struct Rect { int w; int h; }; このクラスのインスタンスを テンプレートに渡したい template< ??? > struct Area { テンプレート引数を static constexpr int value = ???; どう書けばいい? };
  • 19. ◆クラステンプレートにコンパイル時定数を渡すには • クラスを直接テンプレート引数にしてみる template<Rect V> struct Area { static constexpr int value = V.w * V.h; }; static constexpr Rect rect = {10, 20}; static_assert( Area<rect>::value == 200, “” );
  • 20. ◆クラステンプレートにコンパイル時定数を渡すには • クラスを直接テンプレート引数にしてみる template<Rect V> コンパイルエラー!! struct Area { static constexpr int value = V.w * V.h; }; static constexpr Rect rect = {10, 20}; static_assert( Area<rect>::value == 200, “” ); • クラス型をテンプレート引数にすることはできない • 論外
  • 21. ◆クラステンプレートにコンパイル時定数を渡すには • ポインタをテンプレート引数にしてみる template<Rect const* P> struct Area { static constexpr int value = P->w * P->h; }; static constexpr Rect rect = {10, 20}; static_assert( Area<&rect>::value == 200, “” );
  • 22. ◆クラステンプレートにコンパイル時定数を渡すには • ポインタをテンプレート引数にしてみる template<Rect const* P> struct Area { static constexpr int value = P->w * P->h; }; OK! static constexpr Rect rect = {10, 20}; static_assert( Area<&rect>::value == 200, “” ); • ポインタ型をテンプレート引数にすることは可能
  • 23. ◆クラステンプレートにコンパイル時定数を渡すには • ポインタをテンプレート引数にしてみる template<Rect const* P> struct Area { static constexpr int value = P->w * P->h; }; int main() { static constexpr Rect rect = {10, 20}; static_assert( Area<&rect>::value == 200, “” ); }
  • 24. ◆クラステンプレートにコンパイル時定数を渡すには • ポインタをテンプレート引数にしてみる template<Rect const* P> struct Area { static constexpr int value = P->w * P->h; }; int main() { コンパイルエラー!! static constexpr Rect rect = {10, 20}; static_assert( Area<&rect>::value == 200, “” ); } • テンプレート引数に渡せる値 – 整数型 / リンケージを持つオブジェクト • ローカル変数、⼀時オブジェクト、⽂字列リテラル等を テンプレート引数に渡すことはできない
  • 25. ◆クラステンプレートにコンパイル時定数を渡すには • プロキシクラスをテンプレート引数にしてみる template<class Proxy> struct Area { static constexpr int value = Proxy()().w * Proxy()().h; }; int main() { static constexpr Rect rect = {10, 20}; struct proxy { constexpr Rect const& operator()() const { return rect; } }; static_assert( Area<proxy>::value == 200, “” ); }
  • 26. ◆クラステンプレートにコンパイル時定数を渡すには • プロキシクラスをテンプレート引数にしてみる template<class Proxy> struct Area { プロキシを介して値を取得 static constexpr int value = Proxy()().w * Proxy()().h; }; int main() { proxy クラスの operator() は static constexpr Rect rect = {10, 20}; ローカル変数の Rect を返す struct proxy { constexpr Rect const& operator()() const { return rect; } }; static_assert( Area<proxy>::value == 200, “” ); } OK! • 短所 – プロキシクラスをいちいち定義しなければならない
  • 27. ◆クラステンプレートにコンパイル時定数を渡すには • ポインタをテンプレート引数にする⽅法 template<Object const* P> struct TemplateClass; – リンケージを持つオブジェクト(グローバル変数)しか渡すこと ができない • プロキシクラスをテンプレート引数にする⽅法 template<class Proxy> struct TemplateClass; – その都度プロキシクラスを作成する必要がある – (プロキシの定義をマクロにすれば多少書きやすいかも)
  • 28. ◆index_tuple idiom • index_tuple と index_range ヘルパ template<ptrdiff_t... Indexes> struct index_tuple; template<ptrdiff_t First, ptrdiff_t Last> struct index_range; static_assert( std::is_same< index_range<0, 5>::type, index_tuple<0, 1, 2, 3, 4> >::value, “” );
  • 29. ◆index_tuple idiom • index_tuple と index_range ヘルパ template<ptrdiff_t... Indexes> パラメータパックを struct index_tuple; pack expansion expression (Indexes...) で使う template<ptrdiff_t First, ptrdiff_t Last> struct index_range; (First .. Last] の index_tuple を⽣成する static_assert( std::is_same< ヘルパメタ関数 index_range<0, 5>::type, index_tuple<0, 1, 2, 3, 4> >::value, “” );
  • 30. ◆index_tuple idiom • TMP で index_tuple を使う #include <sprout/index_tuple.hpp> #include <boost/mpl/vector.hpp> template<class Seq, class IndexTuple> struct to_tuple_impl; template<class Seq, ptrdiff_t... Indexes> struct to_tuple_impl<Seq, index_tuple<Indexes...> > { typedef tuple< mpl::at_c<Seq, Indexes>... > type; }; /* MPLシーケンスから tuple への変換 */ template<class Seq> struct to_tuple : to_tuple_impl< Seq, typename index_range<0, mpl::size<Seq>::value>::type > { }; typedef mpl::vector<int, double> vec; static_assert( is_same<to_tuple<vec>::type, tuple<int, double> >::value, “” );
  • 31. ◆index_tuple idiom • TMP で index_tuple を使う #include <sprout/index_tuple.hpp> #include <boost/mpl/vector.hpp> index_tuple<Indexes...> で template<class Seq, class IndexTuple> テンプレート引数を特殊化する struct to_tuple_impl; template<class Seq, ptrdiff_t... Indexes> struct to_tuple_impl<Seq, index_tuple<Indexes...> > { typedef tuple< mpl::at_c<Seq, Indexes>... > type; }; /* MPLシーケンスから tuple への変換 */ pack expansion expression で template<class Seq> Indexes を使ったリストに展開する struct to_tuple : to_tuple_impl< Seq, typename index_range<0, mpl::size<Seq>::value>::type > { }; index_range で index_tuple を ⽣成して実装に丸投げ typedef mpl::vector<int, double> vec; static_assert( is_same<to_tuple<vec>::type, tuple<int, double> >::value, “” );
  • 32. ◆index_tuple idiom • constexpr 関数で index_tuple を使う #include <sprout/index_tuple.hpp> #include <sprout/array.hpp> template<class T, size_t N, ptrdiff_t...Indexes> constexpr array<T, N> to_array_impl(T const (& arr)[N], index_tuple<Indexes...>) { return array<T, N>{{ arr[Indexes]... }}; } /* 生配列から sprout::array への変換 */ template<class T, size_t N> constexpr array<T, N> to_array(T const (& arr)[N]) { return to_array_impl(arr, typename index_range<0, N>::type()); } static constexpr int arr[2] = { 1, 2 }; static constexpr array<int, 2> s = to_array(arr);
  • 33. ◆index_tuple idiom • constexpr 関数で index_tuple を使う #include <sprout/index_tuple.hpp> index_tuple<Indexes...> #include <sprout/array.hpp> を引数にして推論させる template<class T, size_t N, ptrdiff_t...Indexes> constexpr array<T, N> to_array_impl(T const (& arr)[N], index_tuple<Indexes...>) { return array<T, N>{{ arr[Indexes]... }}; } pack expansion expression で /* 生配列から sprout::array への変換 */ Indexes を使ったリストに展開する template<class T, size_t N> constexpr array<T, N> to_array(T const (& arr)[N]) { return to_array_impl(arr, typename index_range<0, N>::type()); } index_range で index_tuple を static constexpr int arr[2] = { 1, 2 }; ⽣成して実装に丸投げ static constexpr array<int, 2> s = to_array(arr);
  • 34. ◆index_tuple idiom • index_tuple イディオムは、インデックスアクセス可能 なデータ構造⼀般に適⽤できる – 配列 – タプル – ランダムアクセスイテレータ – 型リスト • constexpr に限らず、通常の関数や TMP にも同じよう に応⽤できる • ただしインデックスアクセス不可なデータ構造には適⽤ できない – ⾮ランダムアクセスなイテレータなど
  • 35. ◆型⽂字列と constexpr ⽂字列の相互変換 • 型⽂字列 typedef mpl::string< ‘Hell’, ‘o,wo’, ‘rld!’ > hello_t; – ⽂字列は可変⻑テンプレート引数で表現される – ⽂字列リテラルは使えない • (マクロの⿊魔術を使えば制限付きで可能ではある) • constexpr ⽂字列 static constexpr auto hello = sprout::to_string( “Hello,world!” ); – コンパイル時定数である – ⽂字列リテラルが使⽤可能 • これらを相互に変換できるようにしたい
  • 36. ◆型⽂字列と constexpr ⽂字列の相互変換 • mpl::string → sprout::string #include <type_traits> #include <sprout/index_tuple.hpp> #include <sprout/type.hpp> #include <sprout/string.hpp> #include <sprout/type/boost/mpl/string.hpp> using namespace std; using namespace sprout; namespace mpl = boost::mpl; namespace types = sprout::types;
  • 37. ◆型⽂字列と constexpr ⽂字列の相互変換 • mpl::string → sprout::string /* T::value がナル文字であるか返すメタ関数クラス */ struct is_nul { template<class T, class = void> struct apply : false_type { }; template<class T> struct apply<T, typename enable_if<T::value == 0>::type> : true_type { }; }; /* ナル文字までの文字列長 */ template<class Seq> struct str_length : types::distance< typename types::begin<Seq>::type, typename types::seq::find_if<Seq, is_nul>::type > { };
  • 38. ◆型⽂字列と constexpr ⽂字列の相互変換 • mpl::string → sprout::string template<class Seq, ptrdiff_t... Indexes> constexpr sprout::basic_string< typename Seq::value_type, str_length<Seq>::value > to_sprout_string_impl( index_tuple<Indexes...> ) { return sprout::make_string_as<typename Seq::value_type>( types::tuple_element<Indexes, Seq>::type::value... ); } /* sprout::string に変換 */ template<class Seq> constexpr sprout::basic_string< typename Seq::value_type, str_length<Seq>::value > to_sprout_string() { return to_sprout_string_impl<Seq>( typename index_range<0, str_length<Seq>::value>::type() ); }
  • 39. ◆型⽂字列と constexpr ⽂字列の相互変換 • mpl::string → sprout::string template<class Seq, ptrdiff_t... Indexes> constexpr sprout::basic_string< index_tuple<Indexes...> を typename Seq::value_type, 実装関数で受け取る str_length<Seq>::value > to_sprout_string_impl( index_tuple<Indexes...> ) { return sprout::make_string_as<typename Seq::value_type>( types::tuple_element<Indexes, Seq>::type::value... ); Indexes を使ってシーケンス要素の } ⽂字のリストに展開 /* sprout::string に変換 */ template<class Seq> constexpr sprout::basic_string< basic_string<Elem, Length> typename Seq::value_type, str_length<Seq>::value index_range で index_tuple を > to_sprout_string() { ⽣成して実装に丸投げ return to_sprout_string_impl<Seq>( typename index_range<0, str_length<Seq>::value>::type() ); }
  • 40. ◆型⽂字列と constexpr ⽂字列の相互変換 • mpl::string → sprout::string typedef mpl::string< ‘foo’, ‘bar’ > type; static constexpr auto s = to_sprout_string<type>(); static_assert( s == “foobar”, “” ); mpl::string (型)から sprout::string (コンパイル時定数)へ変換 • ⼀般に【型→値】の変換は⾃明に書ける(場合が多い)
  • 41. ◆型⽂字列と constexpr ⽂字列の相互変換 • sprout::string → mpl::string #include <type_traits> #include <sprout/index_tuple.hpp> #include <sprout/fixed_container.hpp> #include <sprout/string.hpp> #include <boost/mpl/string.hpp> #include <boost/preprocessor/cat.hpp> using namespace std; using namespace sprout; namespace mpl = boost::mpl;
  • 42. ◆型⽂字列と constexpr ⽂字列の相互変換 • sprout::string → mpl::string template<class Proxy> struct to_mpl_string { template<class IndexTuple> struct impl; template<ptrdiff_t... Indexes> struct impl<index_tuple<Indexes...> > { typedef mpl::string< sprout::begin(Proxy()())[Indexes]... > type; }; /* mpl::string に変換 */ typedef class impl< typename index_range<0, sprout::size(Proxy()())>::type >::type type; };
  • 43. ◆型⽂字列と constexpr ⽂字列の相互変換 • sprout::string → mpl::string template<class Proxy> index_tuple<Indexes...> を struct to_mpl_string { 実装メタ関数で受け取る template<class IndexTuple> struct impl; template<ptrdiff_t... Indexes> struct impl<index_tuple<Indexes...> > { typedef mpl::string< mpl::string<Elem...> sprout::begin(Proxy()())[Indexes]... > type; }; Indexes を使ってシーケンス要素の /* mpl::string に変換 */ ⽂字のリストに展開 typedef class impl< typename index_range<0, sprout::size(Proxy()())>::type >::type type; }; index_range で index_tuple を ⽣成して実装に丸投げ
  • 44. ◆型⽂字列と constexpr ⽂字列の相互変換 • sprout::string → mpl::string /* 変換結果を typedef するマクロ*/ #define STRING_CLASS_TYPEDEF(SOURCE, TYPE) ¥ struct BOOST_PP_CAT(PROXY_, __LINE__) { ¥ constexpr typename remove_reference<decltype(SOURCE)>::type ¥ operator() () const { return SOURCE; } ¥ }; ¥ typedef typename to_mpl_string< ¥ BOOST_PP_CAT(PROXY_, __LINE__) ¥ >::type TYPE
  • 45. ◆型⽂字列と constexpr ⽂字列の相互変換 • sprout::string → mpl::string PROXY_127 のような名前の プロキシクラスが定義される /* 変換結果を typedef するマクロ*/ #define STRING_CLASS_TYPEDEF(SOURCE, TYPE) ¥ struct BOOST_PP_CAT(PROXY_, __LINE__) { ¥ constexpr typename remove_reference<decltype(SOURCE)>::type ¥ operator() () const { return SOURCE; } ¥ }; ¥ operator() は変換元ソースを typedef typename to_mpl_string< ¥ そのまま返す constexpr 関数 BOOST_PP_CAT(PROXY_, __LINE__) ¥ >::type TYPE 定義したプロキシクラスを渡す
  • 46. ◆型⽂字列と constexpr ⽂字列の相互変換 • sprout::string → mpl::string #include <boost/mpl/equal.hpp> sprout::string (コンパイル時定数)から mpl::string (型)へ変換 static constexpr auto s = sprout::to_string( “foobar” ); STRING_CLASS_TYPEDEF(s, type); static_assert( mpl::equal< type, mpl::string<'foo', 'bar'> >::value, “” ); • 【値→型】の変換は⼯夫次第で可能 • ⽋点 – ⾃明な書き⽅ができない(場合が多い) – プロキシクラスの定義が必要な場合、インラインに書けないし、 constexpr 関数の中で使えない
  • 47. ◆constexpr と TMP の連携 • 整数型以外のコンパイル時定数でも、テンプ レートに受け渡す⽅法はある • index_tuple イディオムや、プロキシクラス等 を活⽤することで、constexpr と TMP の間で 相互にやりとりをすることができる
  • 48. ◆(続)constexpr レイトレーシング • Sprout.Darkroom – metatrace という TMP ライブラリを元にした constexpr レイ トレーサーライブラリ
  • 53. ◆(続)constexpr レイトレーシング • エレメント(カラーやスペキュラ)を表現するには template<typename Element, typename Scale> class plaid_element { private: Element elem1_; Element elem2_; Scale scale_; template<typename Unit> constexpr Element calc_1(Unit const& u, Unit const& v) const { return (u >= 0 && v >= 0) || (u < 0 && v < 0) ? elem1_ : elem2_; } public: template<typename Unit> constexpr Element operator() (Unit const& u, Unit const& v) const { return calc_1( (u < 0 ? scale_ + fmod(u, scale_) : fmod(u, scale_)) - scale_ / 2, (v < 0 ? scale_ + fmod(v, scale_) : fmod(v, scale_)) - scale_ / 2 ); } };
  • 54. ◆(続)constexpr レイトレーシング • エレメント(カラーやスペキュラ)を表現するには template<typename Element, typename Scale> class plaid_element { private: 市松模様を表現するエレメント Element elem1_; Element elem2_; 座標を⼆つに分けて Scale scale_; どちらかのエレメント(⽩/⿊など)を返す template<typename Unit> constexpr Element calc_1(Unit const& u, Unit const& v) const { return (u >= 0 && v >= 0) || (u < 0 && v < 0) ? elem1_ : elem2_; エレメントのコンセプトは } uv 座標を受け取って結果を返す public: operator()(u, v) を持つこと template<typename Unit> constexpr Element operator() (Unit const& u, Unit const& v) const { return calc_1( (u < 0 ? scale_ + fmod(u, scale_) : fmod(u, scale_)) - scale_ / 2, (v < 0 ? scale_ + fmod(v, scale_) : fmod(v, scale_)) - scale_ / 2 ); } };
  • 55. ◆(続)constexpr レイトレーシング • テクスチャマップを読み込むには #include <sprout/darkroom.hpp> /* ファイル "earth.tex.hpp" の内容を tex に読み込む */ #define DARKROOM_DEF_LOAD_TEXTURE_IDENTIFIER tex #define DARKROOM_DEF_LOAD_TEXTURE_FILE "earth.tex.hpp" #include DARKROOM_LOAD_TEXTURE – earth.png
  • 56. ◆(続)constexpr レイトレーシング • テクスチャマップを読み込むには #include <sprout/darkroom.hpp> /* ファイル "earth.tex.hpp" の内容を tex に読み込む */ #define DARKROOM_DEF_LOAD_TEXTURE_IDENTIFIER tex #define DARKROOM_DEF_LOAD_TEXTURE_FILE "earth.tex.hpp" #include DARKROOM_LOAD_TEXTURE – 擬似コード /* 実装は include ディレクティブで CVS を取りこむトリックと同じような感じ */ constexpr auto tex { # include "earth.tex.hpp" }; “earth.tex.hpp” の中⾝は コンマ区切りのピクセルデータのようなもの
  • 57. ◆まとめ • constexpr を活⽤することで、『型』 『オブジェクト』『外部データ』等さま ざまなソースを、コンパイル時に相互に 扱うことができる • constexpr でもっともっと遊ぼう!!