Se ha denunciado esta presentación.
Se está descargando tu SlideShare. ×
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Cargando en…3
×

Eche un vistazo a continuación

1 de 16 Anuncio

Más Contenido Relacionado

Presentaciones para usted (20)

A los espectadores también les gustó (15)

Anuncio

Similares a emc++ chapter32 (20)

Más de Tatsuki SHIMIZU (17)

Anuncio

Más reciente (20)

emc++ chapter32

  1. 1. Effective Modern C++ #7Effective Modern C++ #7 2015/07/15 清⽔水超貴@simizut22
  2. 2. ちょっと⾃自⼰己紹介ちょっと⾃自⼰己紹介 清⽔水超貴(@simizut22) 数理計画がお仕事 基本荷物を積む たまにグラフの対称性⾒見つける やっぱり荷物を積む
  3. 3. closureclosureに変数をに変数をmovemoveするならするなら 初期化キャプチャ初期化キャプチャ――を使おうを使おう
  4. 4. 変数を変数をmove capturemove captureしたいしたい class Widget { /* ... */ }; std::unique_ptr< Widget > pw; auto fun = [pw]{ /* do something */ }; 上記コード(compile 不可) container などをcopyしたくない などのとき
  5. 5. 初期化キャプチャの構⽂文初期化キャプチャの構⽂文 value capture reference capture [ data = (expression) ] [&data = (expression)] auto cmp = [eval = [](int i){ return -i;}] (int lhs, int rhs) { return eval(lhs) < eval(rhs);} expression なので lambda を⼊入れるのももちろん可能
  6. 6. ちなみに,最新の gcc/msvc は次もok http://melpon.org/wandbox/permlink/Gmqycg5tbA2iE51S using iVec = std::vector< int >; iVec data = iVec{1, 2, 3, 4, 5}; auto fun = [data{std::move(data)}] { std::copy(std::begin(data), std::end(data), [] () mutable { data.clear(): }}; prog.cc:9:19: warning: direct list initialization of a lambda init-capture will change meaning in a future version of Cla insert an '=' to avoid a change in behavior [-Wfuture-compat] auto f = [data{ std::move(data) } ] { ^ clang だと次の messageが出る ref: N3681 Auto and Braced-Init-Lists N3912 Atuto and Braced-Init-Lists, continued N3922 New Rules for auto deduction from braced-init-list
  7. 7. template< class T > struct wrap { mutable T value_; wrap(T&& v) : value_(std::forward< T >(v)) {} wrap(wrap const& other) : value_(std::move(other.value_)) {} }; struct Widget {}; auto pw = wrap< std::unique_ptr< Widget > >{std::make_unique< Widget >()}; auto fun = [pw]{ /* do something */ } こんな wrapper を書くとか... ref:N3610: Generic lambda-capture initializers C++14 なら,初期化キャプチャーでできる
  8. 8. class Widget { public: /* ... */ bool isValidated() const; bool isProessed() const; bool isAchieved() const; private: /* ... */ }; auto pw = std::make_unique< Widget >(); /** * configure *pw **/ auto func = [pw = std::move(pw)] { return pw->isValidated() && pw->isAchived();}; /** * pw is moved to data member pw of closure **/ こうなる
  9. 9. 上記のコードでは 1. closureにデータメンバー pw を作成して 2. local 変数 pw を move して 3. メンバーpw を初期化 をやっている [pw = std::move(pw)] { /* do something */}; もし configure pw の操作が不要なら, 初期化を capture と同時にやればよい [pw = std::make_unique< Widget >()] () { /* do something */ };
  10. 10. lambdalambda 使わなくていいならクラス書けば解決で使わなくていいならクラス書けば解決で きるきるclass Widget { /* same as before */ }; class IsValAndArch { public: using DataType = std::unique_ptr< Widget >; explicit IsValAndArch(DataType&& dt) : pw(std::move(dt)) {} bool operator()() const { return pw->isValid() && pw->isArchived(); } private: DataType pw; }; auto func = IsValAndArch{ std::unique_ptr< Widget >{new Widget()}}; // auto func = IsValAndArch{ std::make_unique< Widget >() }; 疲れる.やっぱり lambda 使いたい...
  11. 11. それそれ bindbind でできるよでできるよ!!!! 1. (move)キャプチャーしたい変数を bind object 内にmoveする 2. "キャプチャー"した変数の参照をラムダの引数にする をすればよい /** c++ 14 init capture **/ using dVec = std::vector< double >; dVec data; /* configure data */ auto func = [data = std::move(data)] { /* do somthing */ }; /** use std::bind for c++11 **/ using dVec = std::vector< double >; dVec data; /* configure data */ auto func = std::bind([](dVec const&) // (2) ^^^^^^^^^^^^ {/* do somthing */} , std::move(data)); // (1) ^^^^^^^^^^^^^^^ 具体的なコードは以下
  12. 12. bindbind とと closureclosure の違いの違い /** c++ 14 init capture **/ std::vector< double > data; /* cofigure data */ auto func = [data = std::move(data)] { data.clear() }; /** bind version **/ std::vector< double > data; /** config data **/ auto func = std::bind([](std::vector< double > v&) { v.clear(); } , std::move(data)); これを愚直に書き換えると
  13. 13. http://melpon.org/wandbox/permlink/3bIhkKfDDlQhXREr Start prog.cc:7:19: error: member function 'clear' not viable: 'this' argument has type 'const std::__1: { data.clear(); }; ^~~~ /usr/local/libcxx-head/include/c++/v1/vector:735:10: note: 'clear' declared here void clear() _NOEXCEPT ^ 1 error generated. clang3.7.0 build してみた ClosureType::operator() は デフォルトではconst method mutable specifier を付けると non-const method が呼ばれる(上は const method を呼んでる) auto fun = [data = std::move(data)] () mutable { data.clear(); }; // ^^^^^^^ これで⼤大丈夫!(^^)! ** mutable を付けるときには argument parameter list が必要 http://melpon.org/wandbox/permlink/zzoa3WK54NxBz7Ac
  14. 14. bind object の⽣生存期間 auto makeFun() // sorry this is c++14 { std::vector< int > data{1,2,3,4,5}; auto fun = [](const std::vector< int >& v) { std::copy(v.begin(), v.end(), std::ostream_iterator< int >(std::cout, " "));}; return std::bind(fun, std::move(data)); // data is copied in bind obj } auto&& fun = makeFun(); fun(); // ok 先に述べた bind + lambda を⽤用いた⽅方法を使った時 bind object の⽣生存期間 = closure object(first argument )の⽣生存期間 = move "capture" された data の⽣生存期間 がなりたつ 従って,capture された data を closure から呼ぶことに問題はない
  15. 15. 1. c++11 lambda では closure に move-construct はできないけど, bind object にはできる 2. bind-object 内に move-construct してから,lambda に参照渡し することで move キャプチャを模倣できる 3. 上記⽅方法では bind-object の寿命と closure の寿命が同じなの で, move されたデータはキャプチャされたように扱える bindbind によるによる init captureinit capture の模倣の要の模倣の要 点点 * ここまでやったけど Item34 では bind より lambda の⽅方がいいという話をする
  16. 16. Things to RememberThings to Remember closure 内に objects を move するなら c++14 init capture を使おう 直にクラスを書くか bind を使えば init-capture は emulate できる

×