SlideShare uma empresa Scribd logo
1 de 58
Baixar para ler 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 でもっともっと遊ぼう!!
ご清聴
 ありがとう
ございました

Mais conteúdo relacionado

Mais procurados

Effective Modern C++ 勉強会 Item 22
Effective Modern C++ 勉強会 Item 22Effective Modern C++ 勉強会 Item 22
Effective Modern C++ 勉強会 Item 22Keisuke Fukuda
 
すごいConstたのしく使おう!
すごいConstたのしく使おう!すごいConstたのしく使おう!
すごいConstたのしく使おう!Akihiro Nishimura
 
WASM(WebAssembly)入門 ペアリング演算やってみた
WASM(WebAssembly)入門 ペアリング演算やってみたWASM(WebAssembly)入門 ペアリング演算やってみた
WASM(WebAssembly)入門 ペアリング演算やってみたMITSUNARI Shigeo
 
RSA暗号運用でやってはいけない n のこと #ssmjp
RSA暗号運用でやってはいけない n のこと #ssmjpRSA暗号運用でやってはいけない n のこと #ssmjp
RSA暗号運用でやってはいけない n のこと #ssmjpsonickun
 
すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!Genya Murakami
 
Quine・難解プログラミングについて
Quine・難解プログラミングについてQuine・難解プログラミングについて
Quine・難解プログラミングについてmametter
 
Effective Modern C++ 勉強会#3 Item16
Effective Modern C++ 勉強会#3 Item16Effective Modern C++ 勉強会#3 Item16
Effective Modern C++ 勉強会#3 Item16Mitsuru Kariya
 
マルチコアを用いた画像処理
マルチコアを用いた画像処理マルチコアを用いた画像処理
マルチコアを用いた画像処理Norishige Fukushima
 
templateとautoの型推論
templateとautoの型推論templateとautoの型推論
templateとautoの型推論MITSUNARI Shigeo
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門Norishige Fukushima
 
新しい並列for構文のご提案
新しい並列for構文のご提案新しい並列for構文のご提案
新しい並列for構文のご提案yohhoy
 
何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門masayoshi takahashi
 
条件分岐とcmovとmaxps
条件分岐とcmovとmaxps条件分岐とcmovとmaxps
条件分岐とcmovとmaxpsMITSUNARI Shigeo
 
闇魔術を触ってみた
闇魔術を触ってみた闇魔術を触ってみた
闇魔術を触ってみたSatoshi Sato
 
暗号文のままで計算しよう - 準同型暗号入門 -
暗号文のままで計算しよう - 準同型暗号入門 -暗号文のままで計算しよう - 準同型暗号入門 -
暗号文のままで計算しよう - 準同型暗号入門 -MITSUNARI Shigeo
 
AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解MITSUNARI Shigeo
 

Mais procurados (20)

プログラムを高速化する話
プログラムを高速化する話プログラムを高速化する話
プログラムを高速化する話
 
Effective Modern C++ 勉強会 Item 22
Effective Modern C++ 勉強会 Item 22Effective Modern C++ 勉強会 Item 22
Effective Modern C++ 勉強会 Item 22
 
すごいConstたのしく使おう!
すごいConstたのしく使おう!すごいConstたのしく使おう!
すごいConstたのしく使おう!
 
WASM(WebAssembly)入門 ペアリング演算やってみた
WASM(WebAssembly)入門 ペアリング演算やってみたWASM(WebAssembly)入門 ペアリング演算やってみた
WASM(WebAssembly)入門 ペアリング演算やってみた
 
RSA暗号運用でやってはいけない n のこと #ssmjp
RSA暗号運用でやってはいけない n のこと #ssmjpRSA暗号運用でやってはいけない n のこと #ssmjp
RSA暗号運用でやってはいけない n のこと #ssmjp
 
すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!
 
明日使えないすごいビット演算
明日使えないすごいビット演算明日使えないすごいビット演算
明日使えないすごいビット演算
 
Quine・難解プログラミングについて
Quine・難解プログラミングについてQuine・難解プログラミングについて
Quine・難解プログラミングについて
 
Effective Modern C++ 勉強会#3 Item16
Effective Modern C++ 勉強会#3 Item16Effective Modern C++ 勉強会#3 Item16
Effective Modern C++ 勉強会#3 Item16
 
C#で速度を極めるいろは
C#で速度を極めるいろはC#で速度を極めるいろは
C#で速度を極めるいろは
 
マルチコアを用いた画像処理
マルチコアを用いた画像処理マルチコアを用いた画像処理
マルチコアを用いた画像処理
 
LLVM最適化のこつ
LLVM最適化のこつLLVM最適化のこつ
LLVM最適化のこつ
 
templateとautoの型推論
templateとautoの型推論templateとautoの型推論
templateとautoの型推論
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門
 
新しい並列for構文のご提案
新しい並列for構文のご提案新しい並列for構文のご提案
新しい並列for構文のご提案
 
何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門
 
条件分岐とcmovとmaxps
条件分岐とcmovとmaxps条件分岐とcmovとmaxps
条件分岐とcmovとmaxps
 
闇魔術を触ってみた
闇魔術を触ってみた闇魔術を触ってみた
闇魔術を触ってみた
 
暗号文のままで計算しよう - 準同型暗号入門 -
暗号文のままで計算しよう - 準同型暗号入門 -暗号文のままで計算しよう - 準同型暗号入門 -
暗号文のままで計算しよう - 準同型暗号入門 -
 
AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解
 

Semelhante a 中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++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるHideyuki Tanaka
 
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
 

Semelhante a 中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++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISる
 
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
 

中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 でもっともっと遊ぼう!!