2014-05-02-01-本気で move について考える - 5 - project-enigma

2014-05-02-01-本気で move について考える - 5

>> Site top >> weblog >> 月別アーカイブ >> 2014年05月のlog >> 2014-05-02-01-本気で move について考える - 5

最終更新日付:2014/05/02 23:50:00


本気で move について考える - 5

2014 年 05 月 02 日

行き詰まった感じが募ってくると、「まぁ手を動かしてみようや」とか考えてしまうのはいくつになっても直らない。そんなわけで、結局 operator-move とかは中途半端に実装してしまった。もちろん、前回書いたような悩みは継続しているわけで。

 

ひとまずのところ、もういい加減 move および代入について悩むのはやめようかと思っている。Common Lisp は Lisp なのであって、その上に C++ を構築することはできないし、そうすべきでもない。自分は Common Lisp 上で使える STL が欲しいのであって、C++ が使いたいならば C++ を使うべきなのだ。そんなわけで、現時点でわかっていることだけでもやってみて、それで手打ちにしようと考えている。

で、総称関数のメソッドについて。:before とか :after だとかを調べていくうち、 :around が役に立つのではないか、ということがわかってきた。前回のコードに関して言えば、第2パラメータを remove-reference で特定化するメソッドについてのみ :around 指定をしてやれば、標準のメソッドよりは優先されてくれるようなのだ。 前回のコードをまとめてみよう。remove-reference に対するメソッドだけ、:around 指定を追加してある。

;; declaration & default method
(defgeneric operator= (lhs rhs))
(defmethod operator= (lhs rhs)            ; [A]
  (format t "(operator= T T) called.~%")
  rhs)

;; move semantics
(defclass remove-reference () ())
(defmethod operator= :around (lhs (rhs remove-reference))        ; [B]
  (format t "(operator= T remove-reference) called.~%")
  rhs)

;; class foo
(defclass foo () ())
(defmethod operator= ((lhs foo) (rhs foo))        ; [C]
  (format t "(operator= foo foo) called.~%")
  rhs)

;; class bar
(defclass bar () ())
(defmethod operator= ((lhs bar) (rhs bar))        ; [D]
  (format t "(operator= bar bar) called.~%")
  rhs)

 

これで、以下のようなメソッドが追加されても第2パラメータが remove-reference であれば [B] がコールされてくれる。

(defmethod operator= ((lhs foo) rhs)              ; [E]
  (format t "(operator= foo T) called.~%")
  rhs)

* (let ((foo (make-instance 'foo))
        (bar (make-instance 'bar))
        (rm  (make-instance 'remove-reference)))
    (operator= foo foo)
    (operator= bar bar)
    (operator= foo bar)
    (operator= foo  rm)
    (operator= bar  rm)
    (values))

=> (operator= foo foo) called.
   (operator= bar bar) called.
   (operator= foo T) called.
   (operator= T remove-reference) called.
   (operator= T remove-reference) called.

 

B がコールされなくなる唯一(だと思うけど)の状況は、以下のように :around 指定でより特定的なメソッドが追加された場合だ。

(defmethod operator= :around ((lhs foo) (rhs remove-reference))  ; [F]
  (format t "(operator= foo remove-reference) called.~%")
  rhs)

 

しかし、これは明らかに意図的なものと言って良いと思う。やりたかったのは [E] のようなものを追加したことによって意図せず move semantics を破壊してしまうことを防ぐことだ。[F] のようなものを禁止することはできないが、さすがにこれは「わかってやってるよね?」と言えると思う。

さて、これでほぼ代入と move semantics について悩むのも終わりだ。ベースになる部分は実装したので、あとは各種のコンテナに関する operator-move を実装することと、随所に存在する「代入」── これは現在無邪気にも setf で実行してしまっているのだが ── を opr= マクロ呼び出しに置き換えること‥‥‥てそれが一番大変なんだけどな。

 

コメント

このページにコメントする

 

このページのタグ

Page tag : Common Lisp

Page tag : STLとその移植

 

 


Copyright(C) 2005-2017 project-enigma.
Generated by CL-PREFAB.